You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by el...@apache.org on 2014/10/20 03:05:42 UTC
[01/16] ACCUMULO-3242 Add proper retry logic to ZooReader,
ZooReaderWriter and ZooUtil removing the RetryingInstance.
Repository: accumulo
Updated Branches:
refs/heads/1.6 6ad16a9c5 -> 0e4159c3f
refs/heads/master f118b2211 -> 8bea7aba9
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/Master.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/Master.java b/server/master/src/main/java/org/apache/accumulo/master/Master.java
index 2f04922..f894afc 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/Master.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/Master.java
@@ -135,7 +135,7 @@ import com.google.common.collect.Iterables;
/**
* The Master is responsible for assigning and balancing tablets to tablet servers.
- *
+ *
* The master will also coordinate log recoveries and reports general status.
*/
public class Master implements LiveTServerSet.Listener, TableObserver, CurrentState {
@@ -997,7 +997,7 @@ public class Master implements LiveTServerSet.Listener, TableObserver, CurrentSt
try {
final AgeOffStore<Master> store = new AgeOffStore<Master>(new org.apache.accumulo.fate.ZooStore<Master>(ZooUtil.getRoot(instance) + Constants.ZFATE,
- ZooReaderWriter.getRetryingInstance()), 1000 * 60 * 60 * 8);
+ ZooReaderWriter.getInstance()), 1000 * 60 * 60 * 8);
int threads = this.getConfiguration().getConfiguration().getCount(Property.MASTER_FATE_THREADPOOL_SIZE);
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
index 49227ef..ebceaa0 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
@@ -30,73 +30,73 @@ import org.apache.accumulo.server.zookeeper.ZooReaderWriter;
class FinishCancelCompaction extends MasterRepo {
private static final long serialVersionUID = 1L;
private String tableId;
-
+
public FinishCancelCompaction(String tableId) {
this.tableId = tableId;
}
-
+
@Override
public Repo<Master> call(long tid, Master environment) throws Exception {
Utils.getReadLock(tableId, tid).unlock();
return null;
}
-
+
@Override
public void undo(long tid, Master environment) throws Exception {
-
+
}
}
/**
- *
+ *
*/
public class CancelCompactions extends MasterRepo {
-
+
private static final long serialVersionUID = 1L;
private String tableId;
private String namespaceId;
-
+
public CancelCompactions(String tableId) {
this.tableId = tableId;
Instance inst = HdfsZooInstance.getInstance();
this.namespaceId = Tables.getNamespaceId(inst, tableId);
}
-
+
@Override
public long isReady(long tid, Master environment) throws Exception {
return Utils.reserveNamespace(namespaceId, tid, false, true, TableOperation.COMPACT_CANCEL)
+ Utils.reserveTable(tableId, tid, false, true, TableOperation.COMPACT_CANCEL);
}
-
+
@Override
public Repo<Master> call(long tid, Master environment) throws Exception {
String zCompactID = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_COMPACT_ID;
String zCancelID = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + tableId
+ Constants.ZTABLE_COMPACT_CANCEL_ID;
-
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
-
+
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
+
byte[] currentValue = zoo.getData(zCompactID, null);
-
+
String cvs = new String(currentValue, Constants.UTF8);
String[] tokens = cvs.split(",");
final long flushID = Long.parseLong(tokens[0]);
-
+
zoo.mutate(zCancelID, null, null, new Mutator() {
@Override
public byte[] mutate(byte[] currentValue) throws Exception {
long cid = Long.parseLong(new String(currentValue, Constants.UTF8));
-
+
if (cid < flushID)
return Long.toString(flushID).getBytes(Constants.UTF8);
else
return Long.toString(cid).getBytes(Constants.UTF8);
}
});
-
+
return new FinishCancelCompaction(tableId);
}
-
+
@Override
public void undo(long tid, Master environment) throws Exception {
Utils.unreserveNamespace(namespaceId, tid, false);
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/tableOps/CompactRange.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CompactRange.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CompactRange.java
index e3b0405..a643ccb 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CompactRange.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CompactRange.java
@@ -89,7 +89,7 @@ class CompactionDriver extends MasterRepo {
String zCancelID = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + tableId
+ Constants.ZTABLE_COMPACT_CANCEL_ID;
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
if (Long.parseLong(new String(zoo.getData(zCancelID, null))) >= compactId) {
// compaction was canceled
@@ -317,7 +317,7 @@ public class CompactRange extends MasterRepo {
public Repo<Master> call(final long tid, Master environment) throws Exception {
String zTablePath = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_COMPACT_ID;
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
byte[] cid;
try {
cid = zoo.mutate(zTablePath, null, null, new Mutator() {
@@ -362,7 +362,7 @@ public class CompactRange extends MasterRepo {
static void removeIterators(final long txid, String tableId) throws Exception {
String zTablePath = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_COMPACT_ID;
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.mutate(zTablePath, null, null, new Mutator() {
@Override
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameNamespace.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameNamespace.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameNamespace.java
index 41f24cd..d69973b 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameNamespace.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameNamespace.java
@@ -53,7 +53,7 @@ public class RenameNamespace extends MasterRepo {
Instance instance = master.getInstance();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
Utils.tableNameLock.lock();
try {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
index 8c5ed00..b1bbb67 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
@@ -67,7 +67,7 @@ public class RenameTable extends MasterRepo {
throw new ThriftTableOperationException(tableId, oldTableName, TableOperation.RENAME, TableOperationExceptionType.INVALID_NAME,
"Namespace in new table name does not match the old table name");
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
Utils.tableNameLock.lock();
try {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
index c2bb7a9..7ede305 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
@@ -41,7 +41,7 @@ import org.apache.zookeeper.KeeperException;
public class Utils {
private static final byte[] ZERO_BYTE = new byte[] {'0'};
-
+
static void checkTableDoesNotExist(Instance instance, String tableName, String tableId, TableOperation operation) throws ThriftTableOperationException {
String id = Tables.getNameToIdMap(instance).get(tableName);
@@ -54,7 +54,7 @@ public class Utils {
String tableId = null;
try {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
final String ntp = ZooUtil.getRoot(instance) + Constants.ZTABLES;
byte[] nid = zoo.mutate(ntp, ZERO_BYTE, ZooUtil.PUBLIC, new Mutator() {
@Override
@@ -79,7 +79,7 @@ public class Utils {
if (getLock(tableId, tid, writeLock).tryLock()) {
if (tableMustExist) {
Instance instance = HdfsZooInstance.getInstance();
- IZooReaderWriter zk = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zk = ZooReaderWriter.getInstance();
if (!zk.exists(ZooUtil.getRoot(instance) + Constants.ZTABLES + "/" + tableId))
throw new ThriftTableOperationException(tableId, "", op, TableOperationExceptionType.NOTFOUND, "Table does not exist");
}
@@ -103,7 +103,7 @@ public class Utils {
if (getLock(namespaceId, id, writeLock).tryLock()) {
if (mustExist) {
Instance instance = HdfsZooInstance.getInstance();
- IZooReaderWriter zk = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zk = ZooReaderWriter.getInstance();
if (!zk.exists(ZooUtil.getRoot(instance) + Constants.ZNAMESPACES + "/" + namespaceId))
throw new ThriftTableOperationException(namespaceId, "", op, TableOperationExceptionType.NAMESPACE_NOTFOUND, "Namespace does not exist");
}
@@ -119,7 +119,7 @@ public class Utils {
String resvPath = ZooUtil.getRoot(instance) + Constants.ZHDFS_RESERVATIONS + "/"
+ Base64.encodeBase64String(directory.getBytes(Constants.UTF8));
- IZooReaderWriter zk = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zk = ZooReaderWriter.getInstance();
if (ZooReservation.attempt(zk, resvPath, String.format("%016x", tid), "")) {
return 0;
@@ -131,7 +131,7 @@ public class Utils {
Instance instance = HdfsZooInstance.getInstance();
String resvPath = ZooUtil.getRoot(instance) + Constants.ZHDFS_RESERVATIONS + "/"
+ Base64.encodeBase64String(directory.getBytes(Constants.UTF8));
- ZooReservation.release(ZooReaderWriter.getRetryingInstance(), resvPath, String.format("%016x", tid));
+ ZooReservation.release(ZooReaderWriter.getInstance(), resvPath, String.format("%016x", tid));
}
private static Lock getLock(String tableId, long tid, boolean writeLock) throws Exception {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/util/FateAdmin.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/util/FateAdmin.java b/server/master/src/main/java/org/apache/accumulo/master/util/FateAdmin.java
index 759bb70..5ab5d75 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/util/FateAdmin.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/util/FateAdmin.java
@@ -75,7 +75,7 @@ public class FateAdmin {
Instance instance = HdfsZooInstance.getInstance();
String path = ZooUtil.getRoot(instance) + Constants.ZFATE;
String masterPath = ZooUtil.getRoot(instance) + Constants.ZMASTER_LOCK;
- IZooReaderWriter zk = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zk = ZooReaderWriter.getInstance();
ZooStore<Master> zs = new ZooStore<Master>(path, zk);
if (jc.getParsedCommand().equals("fail")) {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java
----------------------------------------------------------------------
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java
index de930aa..0778f5b 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java
@@ -811,7 +811,7 @@ public class Tablet {
void bringMinorCompactionOnline(FileRef tmpDatafile, FileRef newDatafile, FileRef absMergeFile, DataFileValue dfv, CommitSession commitSession, long flushId)
throws IOException {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
if (extent.isRootTablet()) {
try {
if (!zoo.isLockHeld(tabletServer.getLock().getLockID())) {
@@ -977,7 +977,7 @@ public class Tablet {
t1 = System.currentTimeMillis();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
dataSourceDeletions.incrementAndGet();
@@ -2319,7 +2319,7 @@ public class Tablet {
try {
String zTablePath = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + extent.getTableId()
+ Constants.ZTABLE_FLUSH_ID;
- return Long.parseLong(new String(ZooReaderWriter.getRetryingInstance().getData(zTablePath, null), Constants.UTF8));
+ return Long.parseLong(new String(ZooReaderWriter.getInstance().getData(zTablePath, null), Constants.UTF8));
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (NumberFormatException nfe) {
@@ -2338,7 +2338,7 @@ public class Tablet {
+ Constants.ZTABLE_COMPACT_CANCEL_ID;
try {
- return Long.parseLong(new String(ZooReaderWriter.getRetryingInstance().getData(zTablePath, null), Constants.UTF8));
+ return Long.parseLong(new String(ZooReaderWriter.getInstance().getData(zTablePath, null), Constants.UTF8));
} catch (KeeperException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
@@ -2351,7 +2351,7 @@ public class Tablet {
String zTablePath = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + extent.getTableId()
+ Constants.ZTABLE_COMPACT_ID;
- String[] tokens = new String(ZooReaderWriter.getRetryingInstance().getData(zTablePath, null), Constants.UTF8).split(",");
+ String[] tokens = new String(ZooReaderWriter.getInstance().getData(zTablePath, null), Constants.UTF8).split(",");
long compactID = Long.parseLong(tokens[0]);
CompactionIterators iters = new CompactionIterators();
[11/16] git commit: ACCUMULO-3242 Add some tests for ZooReaderWriter
Posted by el...@apache.org.
ACCUMULO-3242 Add some tests for ZooReaderWriter
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/6e716364
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/6e716364
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/6e716364
Branch: refs/heads/1.6
Commit: 6e71636462b3a5886502afcaed008e78ced0b4ef
Parents: c023f74
Author: Josh Elser <el...@apache.org>
Authored: Sat Oct 18 14:17:21 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:16:04 2014 -0400
----------------------------------------------------------------------
.../accumulo/fate/zookeeper/ZooReader.java | 20 +-
.../fate/zookeeper/ZooReaderWriter.java | 6 +-
.../fate/zookeeper/ZooReaderWriterTest.java | 193 +++++++++++++++++++
3 files changed, 208 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/6e716364/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
index 994f395..fd7938a 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
@@ -33,7 +33,7 @@ public class ZooReader implements IZooReader {
protected String keepers;
protected int timeout;
- protected final RetryFactory retryFactory;
+ private final RetryFactory retryFactory;
protected ZooKeeper getSession(String keepers, int timeout, String scheme, byte[] auth) {
return ZooSession.getSession(keepers, timeout, scheme, auth);
@@ -43,6 +43,10 @@ public class ZooReader implements IZooReader {
return getSession(keepers, timeout, null, null);
}
+ protected RetryFactory getRetryFactory() {
+ return retryFactory;
+ }
+
protected void retryOrThrow(Retry retry, KeeperException e) throws KeeperException {
log.warn("Saw (possibly) transient exception communicating with ZooKeeper", e);
if (retry.canRetry()) {
@@ -61,7 +65,7 @@ public class ZooReader implements IZooReader {
@Override
public byte[] getData(String zPath, boolean watch, Stat stat) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().getData(zPath, watch, stat);
@@ -80,7 +84,7 @@ public class ZooReader implements IZooReader {
@Override
public Stat getStatus(String zPath) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().exists(zPath, false);
@@ -99,7 +103,7 @@ public class ZooReader implements IZooReader {
@Override
public Stat getStatus(String zPath, Watcher watcher) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().exists(zPath, watcher);
@@ -118,7 +122,7 @@ public class ZooReader implements IZooReader {
@Override
public List<String> getChildren(String zPath) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().getChildren(zPath, false);
@@ -137,7 +141,7 @@ public class ZooReader implements IZooReader {
@Override
public List<String> getChildren(String zPath, Watcher watcher) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().getChildren(zPath, watcher);
@@ -156,7 +160,7 @@ public class ZooReader implements IZooReader {
@Override
public boolean exists(String zPath) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().exists(zPath, false) != null;
@@ -175,7 +179,7 @@ public class ZooReader implements IZooReader {
@Override
public boolean exists(String zPath, Watcher watcher) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().exists(zPath, watcher) != null;
http://git-wip-us.apache.org/repos/asf/accumulo/blob/6e716364/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
index b29b88a..79c2219 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
@@ -106,7 +106,7 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
@Override
public void delete(String path, int version) throws InterruptedException, KeeperException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
getZooKeeper().delete(path, version);
@@ -137,7 +137,7 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
public byte[] mutate(String zPath, byte[] createValue, List<ACL> acl, Mutator mutator) throws Exception {
if (createValue != null) {
while (true) {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
try {
getZooKeeper().create(zPath, createValue, acl, CreateMode.PERSISTENT);
return createValue;
@@ -157,7 +157,7 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
}
}
do {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
Stat stat = new Stat();
byte[] data = getData(zPath, false, stat);
data = mutator.mutate(data);
http://git-wip-us.apache.org/repos/asf/accumulo/blob/6e716364/fate/src/test/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriterTest.java
----------------------------------------------------------------------
diff --git a/fate/src/test/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriterTest.java b/fate/src/test/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriterTest.java
new file mode 100644
index 0000000..59fb498
--- /dev/null
+++ b/fate/src/test/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriterTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.accumulo.fate.zookeeper;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.accumulo.fate.zookeeper.IZooReaderWriter.Mutator;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.KeeperException.BadVersionException;
+import org.apache.zookeeper.KeeperException.Code;
+import org.apache.zookeeper.KeeperException.ConnectionLossException;
+import org.apache.zookeeper.KeeperException.NoNodeException;
+import org.apache.zookeeper.KeeperException.NodeExistsException;
+import org.apache.zookeeper.KeeperException.SessionExpiredException;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Stat;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ZooReaderWriterTest {
+
+ private ZooReaderWriter zrw;
+ private ZooKeeper zk;
+ private RetryFactory retryFactory;
+ private Retry retry;
+
+ @Before
+ public void setup() {
+ zk = EasyMock.createMock(ZooKeeper.class);
+ zrw = EasyMock.createMockBuilder(ZooReaderWriter.class).addMockedMethods("getRetryFactory", "getZooKeeper").createMock();
+ retryFactory = EasyMock.createMock(RetryFactory.class);
+ retry = EasyMock.createMock(Retry.class);
+
+ EasyMock.expect(zrw.getZooKeeper()).andReturn(zk).anyTimes();
+ EasyMock.expect(zrw.getRetryFactory()).andReturn(retryFactory).anyTimes();
+ EasyMock.expect(retryFactory.create()).andReturn(retry).anyTimes();
+ }
+
+ @Test(expected = NoNodeException.class)
+ public void testDeleteFailOnInitialNoNode() throws Exception {
+ final String path = "/foo";
+ final int version = -1;
+
+ zk.delete(path, version);
+ EasyMock.expectLastCall().andThrow(KeeperException.create(Code.NONODE));
+ EasyMock.expect(retry.hasRetried()).andReturn(false);
+
+ EasyMock.replay(zk, zrw, retryFactory, retry);
+
+ zrw.delete(path, version);
+ }
+
+ @Test
+ public void testDeleteFailOnRetry() throws Exception {
+ final String path = "/foo";
+ final int version = -1;
+
+ zk.delete(path, version);
+ EasyMock.expectLastCall().andThrow(KeeperException.create(Code.CONNECTIONLOSS));
+ EasyMock.expect(retry.canRetry()).andReturn(true);
+ retry.useRetry();
+ EasyMock.expectLastCall().once();
+ retry.waitForNextAttempt();
+ EasyMock.expectLastCall().once();
+ zk.delete(path, version);
+ EasyMock.expectLastCall().andThrow(KeeperException.create(Code.NONODE));
+ EasyMock.expect(retry.hasRetried()).andReturn(true);
+
+ EasyMock.replay(zk, zrw, retryFactory, retry);
+
+ zrw.delete(path, version);
+
+ EasyMock.verify(zk, zrw, retryFactory, retry);
+ }
+
+ @Test(expected = SessionExpiredException.class)
+ public void testMutateNodeCreationFails() throws Exception {
+ final String path = "/foo";
+ final byte[] value = new byte[]{0};
+ final List<ACL> acls = Collections.<ACL> emptyList();
+ Mutator mutator = new Mutator() {
+ @Override
+ public byte[] mutate(byte[] currentValue) throws Exception {
+ return new byte[] {1};
+ }
+ };
+
+ zk.create(path, value, acls, CreateMode.PERSISTENT);
+ EasyMock.expectLastCall().andThrow(new SessionExpiredException()).once();
+ EasyMock.expect(retry.canRetry()).andReturn(false);
+ EasyMock.expect(retry.retriesCompleted()).andReturn(1l).once();
+
+ EasyMock.replay(zk, zrw, retryFactory, retry);
+
+ zrw.mutate(path, value, acls, mutator);
+ }
+
+ @Test
+ public void testMutateWithBadVersion() throws Exception {
+ final String path = "/foo";
+ final byte[] value = new byte[] {0};
+ final List<ACL> acls = Collections.<ACL> emptyList();
+ final byte[] mutatedBytes = new byte[] {1};
+ Mutator mutator = new Mutator() {
+ @Override
+ public byte[] mutate(byte[] currentValue) throws Exception {
+ return mutatedBytes;
+ }
+ };
+
+ Method getDataMethod = ZooReaderWriter.class.getMethod("getData", String.class, boolean.class, Stat.class);
+ zrw = EasyMock.createMockBuilder(ZooReaderWriter.class).addMockedMethods("getRetryFactory", "getZooKeeper").addMockedMethod(getDataMethod).createMock();
+ EasyMock.expect(zrw.getRetryFactory()).andReturn(retryFactory).anyTimes();
+ EasyMock.expect(zrw.getZooKeeper()).andReturn(zk).anyTimes();
+
+ Stat stat = new Stat();
+
+ zk.create(path, value, acls, CreateMode.PERSISTENT);
+ EasyMock.expectLastCall().andThrow(new NodeExistsException()).once();
+ EasyMock.expect(zrw.getData(path, false, stat)).andReturn(new byte[] {3}).times(2);
+ // BadVersionException should retry
+ EasyMock.expect(zk.setData(path, mutatedBytes, 0)).andThrow(new BadVersionException());
+ // Let 2nd setData succeed
+ EasyMock.expect(zk.setData(path, mutatedBytes, 0)).andReturn(null);
+
+ EasyMock.replay(zk, zrw, retryFactory, retry);
+
+ Assert.assertArrayEquals(new byte[] {1}, zrw.mutate(path, value, acls, mutator));
+
+ EasyMock.verify(zk, zrw, retryFactory, retry);
+ }
+
+ @Test
+ public void testMutateWithRetryOnSetData() throws Exception {
+ final String path = "/foo";
+ final byte[] value = new byte[] {0};
+ final List<ACL> acls = Collections.<ACL> emptyList();
+ final byte[] mutatedBytes = new byte[] {1};
+ Mutator mutator = new Mutator() {
+ @Override
+ public byte[] mutate(byte[] currentValue) throws Exception {
+ return mutatedBytes;
+ }
+ };
+
+ Method getDataMethod = ZooReaderWriter.class.getMethod("getData", String.class, boolean.class, Stat.class);
+ zrw = EasyMock.createMockBuilder(ZooReaderWriter.class).addMockedMethods("getRetryFactory", "getZooKeeper").addMockedMethod(getDataMethod).createMock();
+ EasyMock.expect(zrw.getRetryFactory()).andReturn(retryFactory).anyTimes();
+ EasyMock.expect(zrw.getZooKeeper()).andReturn(zk).anyTimes();
+
+ Stat stat = new Stat();
+
+ zk.create(path, value, acls, CreateMode.PERSISTENT);
+ EasyMock.expectLastCall().andThrow(new NodeExistsException()).once();
+ EasyMock.expect(zrw.getData(path, false, stat)).andReturn(new byte[] {3}).times(2);
+ // BadVersionException should retry
+ EasyMock.expect(zk.setData(path, mutatedBytes, 0)).andThrow(new ConnectionLossException());
+
+ EasyMock.expect(retry.canRetry()).andReturn(true);
+ retry.useRetry();
+ EasyMock.expectLastCall();
+ retry.waitForNextAttempt();
+ EasyMock.expectLastCall();
+ // Let 2nd setData succeed
+ EasyMock.expect(zk.setData(path, mutatedBytes, 0)).andReturn(null);
+
+ EasyMock.replay(zk, zrw, retryFactory, retry);
+
+ Assert.assertArrayEquals(new byte[] {1}, zrw.mutate(path, value, acls, mutator));
+
+ EasyMock.verify(zk, zrw, retryFactory, retry);
+ }
+}
[12/16] git commit: ACCUMULO-3242 Fix up the retry logic in ZooCache.
Posted by el...@apache.org.
ACCUMULO-3242 Fix up the retry logic in ZooCache.
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/423cf10a
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/423cf10a
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/423cf10a
Branch: refs/heads/master
Commit: 423cf10a32d062e70ed97d1f85bb3c5c8642acbe
Parents: 1636055
Author: Josh Elser <el...@apache.org>
Authored: Sun Oct 19 12:55:34 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:16:04 2014 -0400
----------------------------------------------------------------------
.../apache/accumulo/fate/zookeeper/ZooCache.java | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/423cf10a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooCache.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooCache.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooCache.java
index d9eb243..b3dd19a 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooCache.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooCache.java
@@ -16,7 +16,6 @@
*/
package org.apache.accumulo.fate.zookeeper;
-import com.google.common.annotations.VisibleForTesting;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -37,6 +36,8 @@ import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
+import com.google.common.annotations.VisibleForTesting;
+
/**
* A cache for values stored in ZooKeeper. Values are kept up to date as they
* change.
@@ -138,6 +139,9 @@ public class ZooCache {
}
private interface ZooRunnable {
+ /**
+ * Runs an operation against ZooKeeper, automatically retrying in the face of KeeperExceptions
+ */
void run(ZooKeeper zooKeeper) throws KeeperException, InterruptedException;
}
@@ -154,8 +158,12 @@ public class ZooCache {
return;
} catch (KeeperException e) {
- if (e.code() == Code.NONODE) {
+ final Code code = e.code();
+ if (code == Code.NONODE) {
log.error("Looked up non-existent node in cache " + e.getPath(), e);
+ } else if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ log.warn("Saw (possibly) transient exception communicating with ZooKeeper, wil retry", e);
+ continue;
}
log.warn("Zookeeper error, will retry", e);
} catch (InterruptedException e) {
@@ -168,7 +176,7 @@ public class ZooCache {
// do not hold lock while sleeping
wait(sleepTime);
} catch (InterruptedException e) {
- e.printStackTrace();
+ log.info("Interrupted waiting before retrying ZooKeeper operation", e);
}
if (sleepTime < 10000)
sleepTime = (int) (sleepTime + sleepTime * Math.random());
@@ -244,7 +252,7 @@ public class ZooCache {
/*
* The following call to exists() is important, since we are caching that a node does not exist. Once the node comes into existence, it will be added to
* the cache. But this notification of a node coming into existence will only be given if exists() was previously called.
- *
+ *
* If the call to exists() is bypassed and only getData() is called with a special case that looks for Code.NONODE in the KeeperException, then
* non-existence can not be cached.
*/
[03/16] ACCUMULO-3242 Add proper retry logic to ZooReader,
ZooReaderWriter and ZooUtil removing the RetryingInstance.
Posted by el...@apache.org.
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/Master.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/Master.java b/server/master/src/main/java/org/apache/accumulo/master/Master.java
index 2f04922..f894afc 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/Master.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/Master.java
@@ -135,7 +135,7 @@ import com.google.common.collect.Iterables;
/**
* The Master is responsible for assigning and balancing tablets to tablet servers.
- *
+ *
* The master will also coordinate log recoveries and reports general status.
*/
public class Master implements LiveTServerSet.Listener, TableObserver, CurrentState {
@@ -997,7 +997,7 @@ public class Master implements LiveTServerSet.Listener, TableObserver, CurrentSt
try {
final AgeOffStore<Master> store = new AgeOffStore<Master>(new org.apache.accumulo.fate.ZooStore<Master>(ZooUtil.getRoot(instance) + Constants.ZFATE,
- ZooReaderWriter.getRetryingInstance()), 1000 * 60 * 60 * 8);
+ ZooReaderWriter.getInstance()), 1000 * 60 * 60 * 8);
int threads = this.getConfiguration().getConfiguration().getCount(Property.MASTER_FATE_THREADPOOL_SIZE);
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
index 49227ef..ebceaa0 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
@@ -30,73 +30,73 @@ import org.apache.accumulo.server.zookeeper.ZooReaderWriter;
class FinishCancelCompaction extends MasterRepo {
private static final long serialVersionUID = 1L;
private String tableId;
-
+
public FinishCancelCompaction(String tableId) {
this.tableId = tableId;
}
-
+
@Override
public Repo<Master> call(long tid, Master environment) throws Exception {
Utils.getReadLock(tableId, tid).unlock();
return null;
}
-
+
@Override
public void undo(long tid, Master environment) throws Exception {
-
+
}
}
/**
- *
+ *
*/
public class CancelCompactions extends MasterRepo {
-
+
private static final long serialVersionUID = 1L;
private String tableId;
private String namespaceId;
-
+
public CancelCompactions(String tableId) {
this.tableId = tableId;
Instance inst = HdfsZooInstance.getInstance();
this.namespaceId = Tables.getNamespaceId(inst, tableId);
}
-
+
@Override
public long isReady(long tid, Master environment) throws Exception {
return Utils.reserveNamespace(namespaceId, tid, false, true, TableOperation.COMPACT_CANCEL)
+ Utils.reserveTable(tableId, tid, false, true, TableOperation.COMPACT_CANCEL);
}
-
+
@Override
public Repo<Master> call(long tid, Master environment) throws Exception {
String zCompactID = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_COMPACT_ID;
String zCancelID = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + tableId
+ Constants.ZTABLE_COMPACT_CANCEL_ID;
-
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
-
+
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
+
byte[] currentValue = zoo.getData(zCompactID, null);
-
+
String cvs = new String(currentValue, Constants.UTF8);
String[] tokens = cvs.split(",");
final long flushID = Long.parseLong(tokens[0]);
-
+
zoo.mutate(zCancelID, null, null, new Mutator() {
@Override
public byte[] mutate(byte[] currentValue) throws Exception {
long cid = Long.parseLong(new String(currentValue, Constants.UTF8));
-
+
if (cid < flushID)
return Long.toString(flushID).getBytes(Constants.UTF8);
else
return Long.toString(cid).getBytes(Constants.UTF8);
}
});
-
+
return new FinishCancelCompaction(tableId);
}
-
+
@Override
public void undo(long tid, Master environment) throws Exception {
Utils.unreserveNamespace(namespaceId, tid, false);
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/tableOps/CompactRange.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CompactRange.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CompactRange.java
index e3b0405..a643ccb 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CompactRange.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CompactRange.java
@@ -89,7 +89,7 @@ class CompactionDriver extends MasterRepo {
String zCancelID = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + tableId
+ Constants.ZTABLE_COMPACT_CANCEL_ID;
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
if (Long.parseLong(new String(zoo.getData(zCancelID, null))) >= compactId) {
// compaction was canceled
@@ -317,7 +317,7 @@ public class CompactRange extends MasterRepo {
public Repo<Master> call(final long tid, Master environment) throws Exception {
String zTablePath = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_COMPACT_ID;
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
byte[] cid;
try {
cid = zoo.mutate(zTablePath, null, null, new Mutator() {
@@ -362,7 +362,7 @@ public class CompactRange extends MasterRepo {
static void removeIterators(final long txid, String tableId) throws Exception {
String zTablePath = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_COMPACT_ID;
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.mutate(zTablePath, null, null, new Mutator() {
@Override
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameNamespace.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameNamespace.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameNamespace.java
index 41f24cd..d69973b 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameNamespace.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameNamespace.java
@@ -53,7 +53,7 @@ public class RenameNamespace extends MasterRepo {
Instance instance = master.getInstance();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
Utils.tableNameLock.lock();
try {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
index 8c5ed00..b1bbb67 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
@@ -67,7 +67,7 @@ public class RenameTable extends MasterRepo {
throw new ThriftTableOperationException(tableId, oldTableName, TableOperation.RENAME, TableOperationExceptionType.INVALID_NAME,
"Namespace in new table name does not match the old table name");
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
Utils.tableNameLock.lock();
try {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java b/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
index c2bb7a9..7ede305 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
@@ -41,7 +41,7 @@ import org.apache.zookeeper.KeeperException;
public class Utils {
private static final byte[] ZERO_BYTE = new byte[] {'0'};
-
+
static void checkTableDoesNotExist(Instance instance, String tableName, String tableId, TableOperation operation) throws ThriftTableOperationException {
String id = Tables.getNameToIdMap(instance).get(tableName);
@@ -54,7 +54,7 @@ public class Utils {
String tableId = null;
try {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
final String ntp = ZooUtil.getRoot(instance) + Constants.ZTABLES;
byte[] nid = zoo.mutate(ntp, ZERO_BYTE, ZooUtil.PUBLIC, new Mutator() {
@Override
@@ -79,7 +79,7 @@ public class Utils {
if (getLock(tableId, tid, writeLock).tryLock()) {
if (tableMustExist) {
Instance instance = HdfsZooInstance.getInstance();
- IZooReaderWriter zk = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zk = ZooReaderWriter.getInstance();
if (!zk.exists(ZooUtil.getRoot(instance) + Constants.ZTABLES + "/" + tableId))
throw new ThriftTableOperationException(tableId, "", op, TableOperationExceptionType.NOTFOUND, "Table does not exist");
}
@@ -103,7 +103,7 @@ public class Utils {
if (getLock(namespaceId, id, writeLock).tryLock()) {
if (mustExist) {
Instance instance = HdfsZooInstance.getInstance();
- IZooReaderWriter zk = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zk = ZooReaderWriter.getInstance();
if (!zk.exists(ZooUtil.getRoot(instance) + Constants.ZNAMESPACES + "/" + namespaceId))
throw new ThriftTableOperationException(namespaceId, "", op, TableOperationExceptionType.NAMESPACE_NOTFOUND, "Namespace does not exist");
}
@@ -119,7 +119,7 @@ public class Utils {
String resvPath = ZooUtil.getRoot(instance) + Constants.ZHDFS_RESERVATIONS + "/"
+ Base64.encodeBase64String(directory.getBytes(Constants.UTF8));
- IZooReaderWriter zk = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zk = ZooReaderWriter.getInstance();
if (ZooReservation.attempt(zk, resvPath, String.format("%016x", tid), "")) {
return 0;
@@ -131,7 +131,7 @@ public class Utils {
Instance instance = HdfsZooInstance.getInstance();
String resvPath = ZooUtil.getRoot(instance) + Constants.ZHDFS_RESERVATIONS + "/"
+ Base64.encodeBase64String(directory.getBytes(Constants.UTF8));
- ZooReservation.release(ZooReaderWriter.getRetryingInstance(), resvPath, String.format("%016x", tid));
+ ZooReservation.release(ZooReaderWriter.getInstance(), resvPath, String.format("%016x", tid));
}
private static Lock getLock(String tableId, long tid, boolean writeLock) throws Exception {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/master/src/main/java/org/apache/accumulo/master/util/FateAdmin.java
----------------------------------------------------------------------
diff --git a/server/master/src/main/java/org/apache/accumulo/master/util/FateAdmin.java b/server/master/src/main/java/org/apache/accumulo/master/util/FateAdmin.java
index 759bb70..5ab5d75 100644
--- a/server/master/src/main/java/org/apache/accumulo/master/util/FateAdmin.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/util/FateAdmin.java
@@ -75,7 +75,7 @@ public class FateAdmin {
Instance instance = HdfsZooInstance.getInstance();
String path = ZooUtil.getRoot(instance) + Constants.ZFATE;
String masterPath = ZooUtil.getRoot(instance) + Constants.ZMASTER_LOCK;
- IZooReaderWriter zk = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zk = ZooReaderWriter.getInstance();
ZooStore<Master> zs = new ZooStore<Master>(path, zk);
if (jc.getParsedCommand().equals("fail")) {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java
----------------------------------------------------------------------
diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java
index de930aa..0778f5b 100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/Tablet.java
@@ -811,7 +811,7 @@ public class Tablet {
void bringMinorCompactionOnline(FileRef tmpDatafile, FileRef newDatafile, FileRef absMergeFile, DataFileValue dfv, CommitSession commitSession, long flushId)
throws IOException {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
if (extent.isRootTablet()) {
try {
if (!zoo.isLockHeld(tabletServer.getLock().getLockID())) {
@@ -977,7 +977,7 @@ public class Tablet {
t1 = System.currentTimeMillis();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
dataSourceDeletions.incrementAndGet();
@@ -2319,7 +2319,7 @@ public class Tablet {
try {
String zTablePath = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + extent.getTableId()
+ Constants.ZTABLE_FLUSH_ID;
- return Long.parseLong(new String(ZooReaderWriter.getRetryingInstance().getData(zTablePath, null), Constants.UTF8));
+ return Long.parseLong(new String(ZooReaderWriter.getInstance().getData(zTablePath, null), Constants.UTF8));
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (NumberFormatException nfe) {
@@ -2338,7 +2338,7 @@ public class Tablet {
+ Constants.ZTABLE_COMPACT_CANCEL_ID;
try {
- return Long.parseLong(new String(ZooReaderWriter.getRetryingInstance().getData(zTablePath, null), Constants.UTF8));
+ return Long.parseLong(new String(ZooReaderWriter.getInstance().getData(zTablePath, null), Constants.UTF8));
} catch (KeeperException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
@@ -2351,7 +2351,7 @@ public class Tablet {
String zTablePath = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + extent.getTableId()
+ Constants.ZTABLE_COMPACT_ID;
- String[] tokens = new String(ZooReaderWriter.getRetryingInstance().getData(zTablePath, null), Constants.UTF8).split(",");
+ String[] tokens = new String(ZooReaderWriter.getInstance().getData(zTablePath, null), Constants.UTF8).split(",");
long compactID = Long.parseLong(tokens[0]);
CompactionIterators iters = new CompactionIterators();
[16/16] git commit: Merge branch '1.6'
Posted by el...@apache.org.
Merge branch '1.6'
Conflicts:
fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooCache.java
server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/8bea7aba
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/8bea7aba
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/8bea7aba
Branch: refs/heads/master
Commit: 8bea7aba937d35f03185321869062ade57f83165
Parents: f118b22 0e4159c
Author: Josh Elser <el...@apache.org>
Authored: Sun Oct 19 20:55:34 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:56:42 2014 -0400
----------------------------------------------------------------------
.../accumulo/fate/zookeeper/IZooReader.java | 20 +-
.../fate/zookeeper/IZooReaderWriter.java | 34 +-
.../apache/accumulo/fate/zookeeper/Retry.java | 97 +++++
.../accumulo/fate/zookeeper/RetryFactory.java | 38 ++
.../zookeeper/RetryingInvocationHandler.java | 63 ---
.../accumulo/fate/zookeeper/ZooCache.java | 14 +-
.../accumulo/fate/zookeeper/ZooQueueLock.java | 20 +-
.../accumulo/fate/zookeeper/ZooReader.java | 137 ++++++-
.../fate/zookeeper/ZooReaderWriter.java | 158 +++++---
.../accumulo/fate/zookeeper/ZooSession.java | 42 +-
.../apache/accumulo/fate/zookeeper/ZooUtil.java | 394 ++++++++++++++-----
.../accumulo/fate/zookeeper/RetryTest.java | 127 ++++++
.../RetryingInvocationHandlerTest.java | 87 ----
.../fate/zookeeper/ZooReaderWriterTest.java | 193 +++++++++
.../org/apache/accumulo/server/Accumulo.java | 2 +-
.../apache/accumulo/server/init/Initialize.java | 4 +-
.../accumulo/server/master/LiveTServerSet.java | 2 +-
.../security/handler/ZKAuthenticator.java | 42 +-
.../server/security/handler/ZKAuthorizor.java | 8 +-
.../server/security/handler/ZKPermHandler.java | 50 +--
.../accumulo/server/tables/TableManager.java | 16 +-
.../server/tablets/UniqueNameAllocator.java | 2 +-
.../accumulo/server/zookeeper/ZooQueueLock.java | 8 +-
.../server/zookeeper/ZooReaderWriter.java | 44 ---
.../zookeeper/ZooReaderWriterFactory.java | 21 -
.../java/org/apache/accumulo/master/Master.java | 4 +-
.../master/tableOps/CancelCompactions.java | 34 +-
.../accumulo/master/tableOps/CompactRange.java | 6 +-
.../master/tableOps/RenameNamespace.java | 2 +-
.../accumulo/master/tableOps/RenameTable.java | 2 +-
.../apache/accumulo/master/tableOps/Utils.java | 12 +-
.../apache/accumulo/master/util/FateAdmin.java | 2 +-
.../tserver/tablet/DatafileManager.java | 4 +-
.../apache/accumulo/tserver/tablet/Tablet.java | 6 +-
34 files changed, 1154 insertions(+), 541 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooCache.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/base/src/main/java/org/apache/accumulo/server/Accumulo.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
index 61c9991,5f6ff71..d46d623
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
@@@ -38,12 -37,12 +38,12 @@@ import org.apache.zookeeper.KeeperExcep
// Utility class for adding all authentication info into ZK
public final class ZKAuthenticator implements Authenticator {
- static final Logger log = Logger.getLogger(ZKAuthenticator.class);
+ private static final Logger log = Logger.getLogger(ZKAuthenticator.class);
private static Authenticator zkAuthenticatorInstance = null;
-
+
private String ZKUserPath;
private final ZooCache zooCache;
-
+
public static synchronized Authenticator getInstance() {
if (zkAuthenticatorInstance == null)
zkAuthenticatorInstance = new ZKAuthenticator();
@@@ -70,10 -69,10 +70,10 @@@
zoo.recursiveDelete(ZKUserPath, NodeMissingPolicy.SKIP);
log.info("Removed " + ZKUserPath + "/" + " from zookeeper");
}
-
+
// prep parent node of users with root username
- zoo.putPersistentData(ZKUserPath, principal.getBytes(Constants.UTF8), NodeExistsPolicy.FAIL);
+ zoo.putPersistentData(ZKUserPath, principal.getBytes(StandardCharsets.UTF_8), NodeExistsPolicy.FAIL);
-
+
constructUser(principal, ZKSecurityTool.createPass(token));
}
} catch (KeeperException e) {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
index 25dbcce,71b7155..7d27909
--- a/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
@@@ -64,9 -63,9 +64,9 @@@ public class TableManager
log.debug("Creating ZooKeeper entries for new namespace " + namespace + " (ID: " + namespaceId + ")");
String zPath = Constants.ZROOT + "/" + instanceId + Constants.ZNAMESPACES + "/" + namespaceId;
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.putPersistentData(zPath, new byte[0], existsPolicy);
- zoo.putPersistentData(zPath + Constants.ZNAMESPACE_NAME, namespace.getBytes(Constants.UTF8), existsPolicy);
+ zoo.putPersistentData(zPath + Constants.ZNAMESPACE_NAME, namespace.getBytes(StandardCharsets.UTF_8), existsPolicy);
zoo.putPersistentData(zPath + Constants.ZNAMESPACE_CONF, new byte[0], existsPolicy);
}
@@@ -77,11 -76,11 +77,11 @@@
Pair<String,String> qualifiedTableName = Tables.qualify(tableName);
tableName = qualifiedTableName.getSecond();
String zTablePath = Constants.ZROOT + "/" + instanceId + Constants.ZTABLES + "/" + tableId;
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.putPersistentData(zTablePath, new byte[0], existsPolicy);
zoo.putPersistentData(zTablePath + Constants.ZTABLE_CONF, new byte[0], existsPolicy);
- zoo.putPersistentData(zTablePath + Constants.ZTABLE_NAMESPACE, namespaceId.getBytes(Constants.UTF8), existsPolicy);
- zoo.putPersistentData(zTablePath + Constants.ZTABLE_NAME, tableName.getBytes(Constants.UTF8), existsPolicy);
+ zoo.putPersistentData(zTablePath + Constants.ZTABLE_NAMESPACE, namespaceId.getBytes(StandardCharsets.UTF_8), existsPolicy);
+ zoo.putPersistentData(zTablePath + Constants.ZTABLE_NAME, tableName.getBytes(StandardCharsets.UTF_8), existsPolicy);
zoo.putPersistentData(zTablePath + Constants.ZTABLE_FLUSH_ID, ZERO_BYTE, existsPolicy);
zoo.putPersistentData(zTablePath + Constants.ZTABLE_COMPACT_ID, ZERO_BYTE, existsPolicy);
zoo.putPersistentData(zTablePath + Constants.ZTABLE_COMPACT_CANCEL_ID, ZERO_BYTE, existsPolicy);
@@@ -133,7 -132,7 +133,7 @@@
String statePath = ZooUtil.getRoot(HdfsZooInstance.getInstance()) + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_STATE;
try {
- ZooReaderWriter.getRetryingInstance().mutate(statePath, newState.name().getBytes(StandardCharsets.UTF_8), ZooUtil.PUBLIC, new Mutator() {
- ZooReaderWriter.getInstance().mutate(statePath, newState.name().getBytes(Constants.UTF8), ZooUtil.PUBLIC, new Mutator() {
++ ZooReaderWriter.getInstance().mutate(statePath, newState.name().getBytes(StandardCharsets.UTF_8), ZooUtil.PUBLIC, new Mutator() {
@Override
public byte[] mutate(byte[] oldData) throws Exception {
TableState oldState = TableState.UNKNOWN;
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java
index 1c1ee62,eabdc0d..38a96d4
--- a/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java
@@@ -49,11 -48,11 +49,11 @@@ public class UniqueNameAllocator
final int allocate = 100 + rand.nextInt(100);
try {
- byte[] max = ZooReaderWriter.getRetryingInstance().mutate(nextNamePath, null, ZooUtil.PRIVATE, new ZooReaderWriter.Mutator() {
+ byte[] max = ZooReaderWriter.getInstance().mutate(nextNamePath, null, ZooUtil.PRIVATE, new ZooReaderWriter.Mutator() {
public byte[] mutate(byte[] currentValue) throws Exception {
- long l = Long.parseLong(new String(currentValue, Constants.UTF8), Character.MAX_RADIX);
+ long l = Long.parseLong(new String(currentValue, StandardCharsets.UTF_8), Character.MAX_RADIX);
l += allocate;
- return Long.toString(l, Character.MAX_RADIX).getBytes(Constants.UTF8);
+ return Long.toString(l, Character.MAX_RADIX).getBytes(StandardCharsets.UTF_8);
}
});
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java
index 53cf1c4,b02e5d4..9a968a9
--- a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java
@@@ -24,15 -24,15 +24,15 @@@ import org.apache.accumulo.fate.zookeep
import org.apache.zookeeper.KeeperException;
public class ZooQueueLock extends org.apache.accumulo.fate.zookeeper.ZooQueueLock {
-
+
public ZooQueueLock(String path, boolean ephemeral) throws KeeperException, InterruptedException {
- super(ZooReaderWriter.getRetryingInstance(), path, ephemeral);
+ super(ZooReaderWriter.getInstance(), path, ephemeral);
}
-
+
public static void main(String args[]) throws InterruptedException, KeeperException {
ZooQueueLock lock = new ZooQueueLock("/lock", true);
- DistributedReadWriteLock rlocker = new DistributedReadWriteLock(lock, "reader".getBytes(Constants.UTF8));
- DistributedReadWriteLock wlocker = new DistributedReadWriteLock(lock, "wlocker".getBytes(Constants.UTF8));
+ DistributedReadWriteLock rlocker = new DistributedReadWriteLock(lock, "reader".getBytes(StandardCharsets.UTF_8));
+ DistributedReadWriteLock wlocker = new DistributedReadWriteLock(lock, "wlocker".getBytes(StandardCharsets.UTF_8));
final Lock readLock = rlocker.readLock();
readLock.lock();
final Lock readLock2 = rlocker.readLock();
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
index 20afc90,435591d..e6d2350
--- a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
@@@ -16,28 -16,18 +16,19 @@@
*/
package org.apache.accumulo.server.zookeeper;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
-import org.apache.accumulo.core.Constants;
+import java.nio.charset.StandardCharsets;
+
import org.apache.accumulo.core.conf.AccumuloConfiguration;
import org.apache.accumulo.core.conf.Property;
-import org.apache.accumulo.server.conf.ServerConfiguration;
+import org.apache.accumulo.core.conf.SiteConfiguration;
- import org.apache.accumulo.fate.util.UtilWaitThread;
- import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
- import org.apache.log4j.Logger;
- import org.apache.zookeeper.KeeperException;
public class ZooReaderWriter extends org.apache.accumulo.fate.zookeeper.ZooReaderWriter {
private static final String SCHEME = "digest";
private static final String USER = "accumulo";
private static ZooReaderWriter instance = null;
- private static IZooReaderWriter retryingInstance = null;
public ZooReaderWriter(String string, int timeInMillis, String secret) {
- super(string, timeInMillis, SCHEME, (USER + ":" + secret).getBytes(Constants.UTF8));
+ super(string, timeInMillis, SCHEME, (USER + ":" + secret).getBytes(StandardCharsets.UTF_8));
}
public static synchronized ZooReaderWriter getInstance() {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
----------------------------------------------------------------------
diff --cc server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
index 8494682,4a7111d..e07c2b9
--- a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
@@@ -16,16 -16,12 +16,13 @@@
*/
package org.apache.accumulo.server.zookeeper;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
-import org.apache.accumulo.core.Constants;
+import java.nio.charset.StandardCharsets;
+
import org.apache.accumulo.core.conf.AccumuloConfiguration;
import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.conf.SiteConfiguration;
import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
- import org.apache.accumulo.fate.zookeeper.RetryingInvocationHandler;
import org.apache.accumulo.fate.zookeeper.ZooReaderWriter;
-import org.apache.accumulo.server.conf.ServerConfiguration;
/**
* A factory for {@link ZooReaderWriter} objects.
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/master/src/main/java/org/apache/accumulo/master/Master.java
----------------------------------------------------------------------
diff --cc server/master/src/main/java/org/apache/accumulo/master/Master.java
index b435b0f,f894afc..42495f4
--- a/server/master/src/main/java/org/apache/accumulo/master/Master.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/Master.java
@@@ -1052,14 -997,13 +1052,14 @@@ public class Master implements LiveTSer
try {
final AgeOffStore<Master> store = new AgeOffStore<Master>(new org.apache.accumulo.fate.ZooStore<Master>(ZooUtil.getRoot(instance) + Constants.ZFATE,
- ZooReaderWriter.getRetryingInstance()), 1000 * 60 * 60 * 8);
+ ZooReaderWriter.getInstance()), 1000 * 60 * 60 * 8);
- int threads = this.getConfiguration().getConfiguration().getCount(Property.MASTER_FATE_THREADPOOL_SIZE);
+ int threads = getConfiguration().getCount(Property.MASTER_FATE_THREADPOOL_SIZE);
- fate = new Fate<Master>(this, store, threads);
+ fate = new Fate<Master>(this, store);
+ fate.startTransactionRunners(threads);
- SimpleTimer.getInstance().schedule(new Runnable() {
+ SimpleTimer.getInstance(getConfiguration()).schedule(new Runnable() {
@Override
public void run() {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
----------------------------------------------------------------------
diff --cc server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
index c6ead8c,ebceaa0..eb49a35
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/CancelCompactions.java
@@@ -75,30 -73,30 +75,30 @@@ public class CancelCompactions extends
String zCompactID = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_COMPACT_ID;
String zCancelID = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + tableId
+ Constants.ZTABLE_COMPACT_CANCEL_ID;
-
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
-
+
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
+
byte[] currentValue = zoo.getData(zCompactID, null);
-
+
- String cvs = new String(currentValue, Constants.UTF8);
+ String cvs = new String(currentValue, StandardCharsets.UTF_8);
String[] tokens = cvs.split(",");
final long flushID = Long.parseLong(tokens[0]);
-
+
zoo.mutate(zCancelID, null, null, new Mutator() {
@Override
public byte[] mutate(byte[] currentValue) throws Exception {
- long cid = Long.parseLong(new String(currentValue, Constants.UTF8));
+ long cid = Long.parseLong(new String(currentValue, StandardCharsets.UTF_8));
-
+
if (cid < flushID)
- return Long.toString(flushID).getBytes(Constants.UTF8);
+ return Long.toString(flushID).getBytes(StandardCharsets.UTF_8);
else
- return Long.toString(cid).getBytes(Constants.UTF8);
+ return Long.toString(cid).getBytes(StandardCharsets.UTF_8);
}
});
-
+
return new FinishCancelCompaction(tableId);
}
-
+
@Override
public void undo(long tid, Master environment) throws Exception {
Utils.unreserveNamespace(namespaceId, tid, false);
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/master/src/main/java/org/apache/accumulo/master/tableOps/CompactRange.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/master/src/main/java/org/apache/accumulo/master/tableOps/RenameTable.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
----------------------------------------------------------------------
diff --cc server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
index a741085,7ede305..6961776
--- a/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
+++ b/server/master/src/main/java/org/apache/accumulo/master/tableOps/Utils.java
@@@ -118,9 -117,9 +118,9 @@@ public class Utils
Instance instance = HdfsZooInstance.getInstance();
String resvPath = ZooUtil.getRoot(instance) + Constants.ZHDFS_RESERVATIONS + "/"
- + Base64.encodeBase64String(directory.getBytes(Constants.UTF8));
+ + Base64.encodeBase64String(directory.getBytes(StandardCharsets.UTF_8));
- IZooReaderWriter zk = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zk = ZooReaderWriter.getInstance();
if (ZooReservation.attempt(zk, resvPath, String.format("%016x", tid), "")) {
return 0;
@@@ -131,8 -130,8 +131,8 @@@
public static void unreserveHdfsDirectory(String directory, long tid) throws KeeperException, InterruptedException {
Instance instance = HdfsZooInstance.getInstance();
String resvPath = ZooUtil.getRoot(instance) + Constants.ZHDFS_RESERVATIONS + "/"
- + Base64.encodeBase64String(directory.getBytes(Constants.UTF8));
+ + Base64.encodeBase64String(directory.getBytes(StandardCharsets.UTF_8));
- ZooReservation.release(ZooReaderWriter.getRetryingInstance(), resvPath, String.format("%016x", tid));
+ ZooReservation.release(ZooReaderWriter.getInstance(), resvPath, String.format("%016x", tid));
}
private static Lock getLock(String tableId, long tid, boolean writeLock) throws Exception {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/DatafileManager.java
----------------------------------------------------------------------
diff --cc server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/DatafileManager.java
index 78a2ed6,0000000..a84f092
mode 100644,000000..100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/DatafileManager.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/DatafileManager.java
@@@ -1,608 -1,0 +1,608 @@@
+/*
+ * 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.accumulo.tserver.tablet;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.apache.accumulo.core.client.Connector;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.data.KeyExtent;
+import org.apache.accumulo.core.metadata.schema.DataFileValue;
+import org.apache.accumulo.core.replication.ReplicationConfigurationUtil;
+import org.apache.accumulo.core.replication.StatusUtil;
+import org.apache.accumulo.core.security.Credentials;
+import org.apache.accumulo.core.util.MapCounter;
+import org.apache.accumulo.core.util.Pair;
+import org.apache.accumulo.core.util.UtilWaitThread;
+import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
+import org.apache.accumulo.server.ServerConstants;
+import org.apache.accumulo.server.client.HdfsZooInstance;
+import org.apache.accumulo.server.fs.FileRef;
+import org.apache.accumulo.server.fs.VolumeManager;
+import org.apache.accumulo.server.master.state.TServerInstance;
+import org.apache.accumulo.server.security.SystemCredentials;
+import org.apache.accumulo.server.util.MasterMetadataUtil;
+import org.apache.accumulo.server.util.MetadataTableUtil;
+import org.apache.accumulo.server.util.ReplicationTableUtil;
+import org.apache.accumulo.server.zookeeper.ZooReaderWriter;
+import org.apache.accumulo.trace.instrument.Span;
+import org.apache.accumulo.trace.instrument.Trace;
+import org.apache.accumulo.tserver.TLevel;
+import org.apache.hadoop.fs.Path;
+import org.apache.log4j.Logger;
+
+class DatafileManager {
+ private final Logger log = Logger.getLogger(DatafileManager.class);
+ // access to datafilesizes needs to be synchronized: see CompactionRunner#getNumFiles
+ private final Map<FileRef,DataFileValue> datafileSizes = Collections.synchronizedMap(new TreeMap<FileRef,DataFileValue>());
+ private final Tablet tablet;
+
+ // ensure we only have one reader/writer of our bulk file notes at at time
+ private final Object bulkFileImportLock = new Object();
+
+ DatafileManager(Tablet tablet, SortedMap<FileRef,DataFileValue> datafileSizes) {
+ for (Entry<FileRef,DataFileValue> datafiles : datafileSizes.entrySet()) {
+ this.datafileSizes.put(datafiles.getKey(), datafiles.getValue());
+ }
+ this.tablet = tablet;
+ }
+
+ private FileRef mergingMinorCompactionFile = null;
+ private final Set<FileRef> filesToDeleteAfterScan = new HashSet<FileRef>();
+ private final Map<Long,Set<FileRef>> scanFileReservations = new HashMap<Long,Set<FileRef>>();
+ private final MapCounter<FileRef> fileScanReferenceCounts = new MapCounter<FileRef>();
+ private long nextScanReservationId = 0;
+ private boolean reservationsBlocked = false;
+
+ private final Set<FileRef> majorCompactingFiles = new HashSet<FileRef>();
+
+ static void rename(VolumeManager fs, Path src, Path dst) throws IOException {
+ if (!fs.rename(src, dst)) {
+ throw new IOException("Rename " + src + " to " + dst + " returned false ");
+ }
+ }
+
+ Pair<Long,Map<FileRef,DataFileValue>> reserveFilesForScan() {
+ synchronized (tablet) {
+
+ while (reservationsBlocked) {
+ try {
+ tablet.wait(50);
+ } catch (InterruptedException e) {
+ log.warn(e, e);
+ }
+ }
+
+ Set<FileRef> absFilePaths = new HashSet<FileRef>(datafileSizes.keySet());
+
+ long rid = nextScanReservationId++;
+
+ scanFileReservations.put(rid, absFilePaths);
+
+ Map<FileRef,DataFileValue> ret = new HashMap<FileRef,DataFileValue>();
+
+ for (FileRef path : absFilePaths) {
+ fileScanReferenceCounts.increment(path, 1);
+ ret.put(path, datafileSizes.get(path));
+ }
+
+ return new Pair<Long,Map<FileRef,DataFileValue>>(rid, ret);
+ }
+ }
+
+ void returnFilesForScan(Long reservationId) {
+
+ final Set<FileRef> filesToDelete = new HashSet<FileRef>();
+
+ synchronized (tablet) {
+ Set<FileRef> absFilePaths = scanFileReservations.remove(reservationId);
+
+ if (absFilePaths == null)
+ throw new IllegalArgumentException("Unknown scan reservation id " + reservationId);
+
+ boolean notify = false;
+ for (FileRef path : absFilePaths) {
+ long refCount = fileScanReferenceCounts.decrement(path, 1);
+ if (refCount == 0) {
+ if (filesToDeleteAfterScan.remove(path))
+ filesToDelete.add(path);
+ notify = true;
+ } else if (refCount < 0)
+ throw new IllegalStateException("Scan ref count for " + path + " is " + refCount);
+ }
+
+ if (notify)
+ tablet.notifyAll();
+ }
+
+ if (filesToDelete.size() > 0) {
+ log.debug("Removing scan refs from metadata " + tablet.getExtent() + " " + filesToDelete);
+ MetadataTableUtil.removeScanFiles(tablet.getExtent(), filesToDelete, SystemCredentials.get(), tablet.getTabletServer().getLock());
+ }
+ }
+
+ void removeFilesAfterScan(Set<FileRef> scanFiles) {
+ if (scanFiles.size() == 0)
+ return;
+
+ Set<FileRef> filesToDelete = new HashSet<FileRef>();
+
+ synchronized (tablet) {
+ for (FileRef path : scanFiles) {
+ if (fileScanReferenceCounts.get(path) == 0)
+ filesToDelete.add(path);
+ else
+ filesToDeleteAfterScan.add(path);
+ }
+ }
+
+ if (filesToDelete.size() > 0) {
+ log.debug("Removing scan refs from metadata " + tablet.getExtent() + " " + filesToDelete);
+ MetadataTableUtil.removeScanFiles(tablet.getExtent(), filesToDelete, SystemCredentials.get(), tablet.getTabletServer().getLock());
+ }
+ }
+
+ private TreeSet<FileRef> waitForScansToFinish(Set<FileRef> pathsToWaitFor, boolean blockNewScans, long maxWaitTime) {
+ long startTime = System.currentTimeMillis();
+ TreeSet<FileRef> inUse = new TreeSet<FileRef>();
+
+ Span waitForScans = Trace.start("waitForScans");
+ try {
+ synchronized (tablet) {
+ if (blockNewScans) {
+ if (reservationsBlocked)
+ throw new IllegalStateException();
+
+ reservationsBlocked = true;
+ }
+
+ for (FileRef path : pathsToWaitFor) {
+ while (fileScanReferenceCounts.get(path) > 0 && System.currentTimeMillis() - startTime < maxWaitTime) {
+ try {
+ tablet.wait(100);
+ } catch (InterruptedException e) {
+ log.warn(e, e);
+ }
+ }
+ }
+
+ for (FileRef path : pathsToWaitFor) {
+ if (fileScanReferenceCounts.get(path) > 0)
+ inUse.add(path);
+ }
+
+ if (blockNewScans) {
+ reservationsBlocked = false;
+ tablet.notifyAll();
+ }
+
+ }
+ } finally {
+ waitForScans.stop();
+ }
+ return inUse;
+ }
+
+ public void importMapFiles(long tid, Map<FileRef,DataFileValue> pathsString, boolean setTime) throws IOException {
+
+ final KeyExtent extent = tablet.getExtent();
+ String bulkDir = null;
+
+ Map<FileRef,DataFileValue> paths = new HashMap<FileRef,DataFileValue>();
+ for (Entry<FileRef,DataFileValue> entry : pathsString.entrySet())
+ paths.put(entry.getKey(), entry.getValue());
+
+ for (FileRef tpath : paths.keySet()) {
+
+ boolean inTheRightDirectory = false;
+ Path parent = tpath.path().getParent().getParent();
+ for (String tablesDir : ServerConstants.getTablesDirs()) {
+ if (parent.equals(new Path(tablesDir, tablet.getExtent().getTableId().toString()))) {
+ inTheRightDirectory = true;
+ break;
+ }
+ }
+ if (!inTheRightDirectory) {
+ throw new IOException("Data file " + tpath + " not in table dirs");
+ }
+
+ if (bulkDir == null)
+ bulkDir = tpath.path().getParent().toString();
+ else if (!bulkDir.equals(tpath.path().getParent().toString()))
+ throw new IllegalArgumentException("bulk files in different dirs " + bulkDir + " " + tpath);
+
+ }
+
+ if (tablet.getExtent().isRootTablet()) {
+ throw new IllegalArgumentException("Can not import files to root tablet");
+ }
+
+ synchronized (bulkFileImportLock) {
+ Credentials creds = SystemCredentials.get();
+ Connector conn;
+ try {
+ conn = HdfsZooInstance.getInstance().getConnector(creds.getPrincipal(), creds.getToken());
+ } catch (Exception ex) {
+ throw new IOException(ex);
+ }
+ // Remove any bulk files we've previously loaded and compacted away
+ List<FileRef> files = MetadataTableUtil.getBulkFilesLoaded(conn, extent, tid);
+
+ for (FileRef file : files)
+ if (paths.keySet().remove(file))
+ log.debug("Ignoring request to re-import a file already imported: " + extent + ": " + file);
+
+ if (paths.size() > 0) {
+ long bulkTime = Long.MIN_VALUE;
+ if (setTime) {
+ for (DataFileValue dfv : paths.values()) {
+ long nextTime = tablet.getAndUpdateTime();
+ if (nextTime < bulkTime)
+ throw new IllegalStateException("Time went backwards unexpectedly " + nextTime + " " + bulkTime);
+ bulkTime = nextTime;
+ dfv.setTime(bulkTime);
+ }
+ }
+
+ tablet.updatePersistedTime(bulkTime, paths, tid);
+ }
+ }
+
+ synchronized (tablet) {
+ for (Entry<FileRef,DataFileValue> tpath : paths.entrySet()) {
+ if (datafileSizes.containsKey(tpath.getKey())) {
+ log.error("Adding file that is already in set " + tpath.getKey());
+ }
+ datafileSizes.put(tpath.getKey(), tpath.getValue());
+
+ }
+
+ tablet.getTabletResources().importedMapFiles();
+
+ tablet.computeNumEntries();
+ }
+
+ for (Entry<FileRef,DataFileValue> entry : paths.entrySet()) {
+ log.log(TLevel.TABLET_HIST, tablet.getExtent() + " import " + entry.getKey() + " " + entry.getValue());
+ }
+ }
+
+ FileRef reserveMergingMinorCompactionFile() {
+ if (mergingMinorCompactionFile != null)
+ throw new IllegalStateException("Tried to reserve merging minor compaction file when already reserved : " + mergingMinorCompactionFile);
+
+ if (tablet.getExtent().isRootTablet())
+ return null;
+
+ int maxFiles = tablet.getTableConfiguration().getMaxFilesPerTablet();
+
+ // when a major compaction is running and we are at max files, write out
+ // one extra file... want to avoid the case where major compaction is
+ // compacting everything except for the largest file, and therefore the
+ // largest file is returned for merging.. the following check mostly
+ // avoids this case, except for the case where major compactions fail or
+ // are canceled
+ if (majorCompactingFiles.size() > 0 && datafileSizes.size() == maxFiles)
+ return null;
+
+ if (datafileSizes.size() >= maxFiles) {
+ // find the smallest file
+
+ long min = Long.MAX_VALUE;
+ FileRef minName = null;
+
+ for (Entry<FileRef,DataFileValue> entry : datafileSizes.entrySet()) {
+ if (entry.getValue().getSize() < min && !majorCompactingFiles.contains(entry.getKey())) {
+ min = entry.getValue().getSize();
+ minName = entry.getKey();
+ }
+ }
+
+ if (minName == null)
+ return null;
+
+ mergingMinorCompactionFile = minName;
+ return minName;
+ }
+
+ return null;
+ }
+
+ void unreserveMergingMinorCompactionFile(FileRef file) {
+ if ((file == null && mergingMinorCompactionFile != null) || (file != null && mergingMinorCompactionFile == null)
+ || (file != null && mergingMinorCompactionFile != null && !file.equals(mergingMinorCompactionFile)))
+ throw new IllegalStateException("Disagreement " + file + " " + mergingMinorCompactionFile);
+
+ mergingMinorCompactionFile = null;
+ }
+
+ void bringMinorCompactionOnline(FileRef tmpDatafile, FileRef newDatafile, FileRef absMergeFile, DataFileValue dfv, CommitSession commitSession, long flushId)
+ throws IOException {
+
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
++ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
+ if (tablet.getExtent().isRootTablet()) {
+ try {
+ if (!zoo.isLockHeld(tablet.getTabletServer().getLock().getLockID())) {
+ throw new IllegalStateException();
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Can not bring major compaction online, lock not held", e);
+ }
+ }
+
+ // rename before putting in metadata table, so files in metadata table should
+ // always exist
+ do {
+ try {
+ if (dfv.getNumEntries() == 0) {
+ tablet.getTabletServer().getFileSystem().deleteRecursively(tmpDatafile.path());
+ } else {
+ if (tablet.getTabletServer().getFileSystem().exists(newDatafile.path())) {
+ log.warn("Target map file already exist " + newDatafile);
+ tablet.getTabletServer().getFileSystem().deleteRecursively(newDatafile.path());
+ }
+
+ rename(tablet.getTabletServer().getFileSystem(), tmpDatafile.path(), newDatafile.path());
+ }
+ break;
+ } catch (IOException ioe) {
+ log.warn("Tablet " + tablet.getExtent() + " failed to rename " + newDatafile + " after MinC, will retry in 60 secs...", ioe);
+ UtilWaitThread.sleep(60 * 1000);
+ }
+ } while (true);
+
+ long t1, t2;
+
+ // the code below always assumes merged files are in use by scans... this must be done
+ // because the in memory list of files is not updated until after the metadata table
+ // therefore the file is available to scans until memory is updated, but want to ensure
+ // the file is not available for garbage collection... if memory were updated
+ // before this point (like major compactions do), then the following code could wait
+ // for scans to finish like major compactions do.... used to wait for scans to finish
+ // here, but that was incorrect because a scan could start after waiting but before
+ // memory was updated... assuming the file is always in use by scans leads to
+ // one uneeded metadata update when it was not actually in use
+ Set<FileRef> filesInUseByScans = Collections.emptySet();
+ if (absMergeFile != null)
+ filesInUseByScans = Collections.singleton(absMergeFile);
+
+ // very important to write delete entries outside of log lock, because
+ // this metadata write does not go up... it goes sideways or to itself
+ if (absMergeFile != null)
+ MetadataTableUtil.addDeleteEntries(tablet.getExtent(), Collections.singleton(absMergeFile), SystemCredentials.get());
+
+ Set<String> unusedWalLogs = tablet.beginClearingUnusedLogs();
+ boolean replicate = ReplicationConfigurationUtil.isEnabled(tablet.getExtent(), tablet.getTableConfiguration());
+ Set<String> logFileOnly = null;
+ if (replicate) {
+ // unusedWalLogs is of the form host/fileURI, need to strip off the host portion
+ logFileOnly = new HashSet<>();
+ for (String unusedWalLog : unusedWalLogs) {
+ int index = unusedWalLog.indexOf('/');
+ if (-1 == index) {
+ log.warn("Could not find host component to strip from DFSLogger representation of WAL");
+ } else {
+ unusedWalLog = unusedWalLog.substring(index + 1);
+ }
+ logFileOnly.add(unusedWalLog);
+ }
+ }
+ try {
+ // the order of writing to metadata and walog is important in the face of machine/process failures
+ // need to write to metadata before writing to walog, when things are done in the reverse order
+ // data could be lost... the minor compaction start even should be written before the following metadata
+ // write is made
+
+ tablet.updateTabletDataFile(commitSession.getMaxCommittedTime(), newDatafile, absMergeFile, dfv, unusedWalLogs, filesInUseByScans, flushId);
+
+ // Mark that we have data we want to replicate
+ // This WAL could still be in use by other Tablets *from the same table*, so we can only mark that there is data to replicate,
+ // but it is *not* closed
+ if (replicate) {
+ if (log.isDebugEnabled()) {
+ log.debug("Recording that data has been ingested into " + tablet.getExtent() + " using " + logFileOnly);
+ }
+ ReplicationTableUtil.updateFiles(SystemCredentials.get(), tablet.getExtent(), logFileOnly, StatusUtil.openWithUnknownLength());
+ }
+ } finally {
+ tablet.finishClearingUnusedLogs();
+ }
+
+ do {
+ try {
+ // the purpose of making this update use the new commit session, instead of the old one passed in,
+ // is because the new one will reference the logs used by current memory...
+
+ tablet.getTabletServer().minorCompactionFinished(tablet.getTabletMemory().getCommitSession(), newDatafile.toString(), commitSession.getWALogSeq() + 2);
+ break;
+ } catch (IOException e) {
+ log.error("Failed to write to write-ahead log " + e.getMessage() + " will retry", e);
+ UtilWaitThread.sleep(1 * 1000);
+ }
+ } while (true);
+
+ synchronized (tablet) {
+ t1 = System.currentTimeMillis();
+
+ if (datafileSizes.containsKey(newDatafile)) {
+ log.error("Adding file that is already in set " + newDatafile);
+ }
+
+ if (dfv.getNumEntries() > 0) {
+ datafileSizes.put(newDatafile, dfv);
+ }
+
+ if (absMergeFile != null) {
+ datafileSizes.remove(absMergeFile);
+ }
+
+ unreserveMergingMinorCompactionFile(absMergeFile);
+
+ tablet.flushComplete(flushId);
+
+ t2 = System.currentTimeMillis();
+ }
+
+ // must do this after list of files in memory is updated above
+ removeFilesAfterScan(filesInUseByScans);
+
+ if (absMergeFile != null)
+ log.log(TLevel.TABLET_HIST, tablet.getExtent() + " MinC [" + absMergeFile + ",memory] -> " + newDatafile);
+ else
+ log.log(TLevel.TABLET_HIST, tablet.getExtent() + " MinC [memory] -> " + newDatafile);
+ log.debug(String.format("MinC finish lock %.2f secs %s", (t2 - t1) / 1000.0, tablet.getExtent().toString()));
+ long splitSize = tablet.getTableConfiguration().getMemoryInBytes(Property.TABLE_SPLIT_THRESHOLD);
+ if (dfv.getSize() > splitSize) {
+ log.debug(String.format("Minor Compaction wrote out file larger than split threshold. split threshold = %,d file size = %,d", splitSize, dfv.getSize()));
+ }
+ }
+
+ public void reserveMajorCompactingFiles(Collection<FileRef> files) {
+ if (majorCompactingFiles.size() != 0)
+ throw new IllegalStateException("Major compacting files not empty " + majorCompactingFiles);
+
+ if (mergingMinorCompactionFile != null && files.contains(mergingMinorCompactionFile))
+ throw new IllegalStateException("Major compaction tried to resrve file in use by minor compaction " + mergingMinorCompactionFile);
+
+ majorCompactingFiles.addAll(files);
+ }
+
+ public void clearMajorCompactingFile() {
+ majorCompactingFiles.clear();
+ }
+
+ void bringMajorCompactionOnline(Set<FileRef> oldDatafiles, FileRef tmpDatafile, FileRef newDatafile, Long compactionId, DataFileValue dfv)
+ throws IOException {
+ final KeyExtent extent = tablet.getExtent();
+ long t1, t2;
+
+ if (!extent.isRootTablet()) {
+
+ if (tablet.getTabletServer().getFileSystem().exists(newDatafile.path())) {
+ log.error("Target map file already exist " + newDatafile, new Exception());
+ throw new IllegalStateException("Target map file already exist " + newDatafile);
+ }
+
+ // rename before putting in metadata table, so files in metadata table should
+ // always exist
+ rename(tablet.getTabletServer().getFileSystem(), tmpDatafile.path(), newDatafile.path());
+
+ if (dfv.getNumEntries() == 0) {
+ tablet.getTabletServer().getFileSystem().deleteRecursively(newDatafile.path());
+ }
+ }
+
+ TServerInstance lastLocation = null;
+ synchronized (tablet) {
+
+ t1 = System.currentTimeMillis();
+
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
++ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
+
+ tablet.incrementDataSourceDeletions();
+
+ if (extent.isRootTablet()) {
+
+ waitForScansToFinish(oldDatafiles, true, Long.MAX_VALUE);
+
+ try {
+ if (!zoo.isLockHeld(tablet.getTabletServer().getLock().getLockID())) {
+ throw new IllegalStateException();
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Can not bring major compaction online, lock not held", e);
+ }
+
+ // mark files as ready for deletion, but
+ // do not delete them until we successfully
+ // rename the compacted map file, in case
+ // the system goes down
+
+ RootFiles.replaceFiles(tablet.getTableConfiguration(), tablet.getTabletServer().getFileSystem(), tablet.getLocation(), oldDatafiles, tmpDatafile, newDatafile);
+ }
+
+ // atomically remove old files and add new file
+ for (FileRef oldDatafile : oldDatafiles) {
+ if (!datafileSizes.containsKey(oldDatafile)) {
+ log.error("file does not exist in set " + oldDatafile);
+ }
+ datafileSizes.remove(oldDatafile);
+ majorCompactingFiles.remove(oldDatafile);
+ }
+
+ if (datafileSizes.containsKey(newDatafile)) {
+ log.error("Adding file that is already in set " + newDatafile);
+ }
+
+ if (dfv.getNumEntries() > 0) {
+ datafileSizes.put(newDatafile, dfv);
+ }
+
+ // could be used by a follow on compaction in a multipass compaction
+ majorCompactingFiles.add(newDatafile);
+
+ tablet.computeNumEntries();
+
+ lastLocation = tablet.resetLastLocation();
+
+ tablet.setLastCompactionID(compactionId);
+ t2 = System.currentTimeMillis();
+ }
+
+ if (!extent.isRootTablet()) {
+ Set<FileRef> filesInUseByScans = waitForScansToFinish(oldDatafiles, false, 10000);
+ if (filesInUseByScans.size() > 0)
+ log.debug("Adding scan refs to metadata " + extent + " " + filesInUseByScans);
+ MasterMetadataUtil.replaceDatafiles(extent, oldDatafiles, filesInUseByScans, newDatafile, compactionId, dfv, SystemCredentials.get(),
+ tablet.getTabletServer().getClientAddressString(), lastLocation, tablet.getTabletServer().getLock());
+ removeFilesAfterScan(filesInUseByScans);
+ }
+
+ log.debug(String.format("MajC finish lock %.2f secs", (t2 - t1) / 1000.0));
+ log.log(TLevel.TABLET_HIST, extent + " MajC " + oldDatafiles + " --> " + newDatafile);
+ }
+
+ public SortedMap<FileRef,DataFileValue> getDatafileSizes() {
+ synchronized (tablet) {
+ TreeMap<FileRef,DataFileValue> copy = new TreeMap<FileRef,DataFileValue>(datafileSizes);
+ return Collections.unmodifiableSortedMap(copy);
+ }
+ }
+
+ public Set<FileRef> getFiles() {
+ synchronized (tablet) {
+ HashSet<FileRef> files = new HashSet<FileRef>(datafileSizes.keySet());
+ return Collections.unmodifiableSet(files);
+ }
+ }
+
+ public int getNumFiles() {
+ return datafileSizes.size();
+ }
+
+}
[02/16] git commit: ACCUMULO-3242 Add proper retry logic to ZooReader,
ZooReaderWriter and ZooUtil removing the RetryingInstance.
Posted by el...@apache.org.
ACCUMULO-3242 Add proper retry logic to ZooReader, ZooReaderWriter and ZooUtil removing the RetryingInstance.
The RetryingInvocationHandler was a nice way to encapsulate retry logic
on a ZooKeeper; however it fails when you actually need to do additional
handling of the KeeperException. Removing the retrying/non-retrying logic
also simplifies methods that the clients can interact with.
ZooUtil still has some unaddressed issues, but I left some TODOs
in place to mark what still needs to be fixed, usually WRT to
session expirations.
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/c023f74e
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/c023f74e
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/c023f74e
Branch: refs/heads/1.6
Commit: c023f74e4329b8c764c46f9468681b71762e976a
Parents: 6ad16a9
Author: Josh Elser <el...@apache.org>
Authored: Fri Oct 17 01:22:15 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:15:59 2014 -0400
----------------------------------------------------------------------
.../accumulo/fate/zookeeper/IZooReader.java | 20 +-
.../apache/accumulo/fate/zookeeper/Retry.java | 74 +++++
.../accumulo/fate/zookeeper/RetryFactory.java | 36 +++
.../zookeeper/RetryingInvocationHandler.java | 63 ----
.../accumulo/fate/zookeeper/ZooQueueLock.java | 20 +-
.../accumulo/fate/zookeeper/ZooReader.java | 133 +++++++-
.../fate/zookeeper/ZooReaderWriter.java | 129 +++++---
.../accumulo/fate/zookeeper/ZooSession.java | 42 +--
.../apache/accumulo/fate/zookeeper/ZooUtil.java | 301 ++++++++++++++-----
.../RetryingInvocationHandlerTest.java | 87 ------
.../org/apache/accumulo/server/Accumulo.java | 2 +-
.../accumulo/server/master/LiveTServerSet.java | 2 +-
.../security/handler/ZKAuthenticator.java | 42 +--
.../server/security/handler/ZKAuthorizor.java | 8 +-
.../server/security/handler/ZKPermHandler.java | 42 +--
.../accumulo/server/tables/TableManager.java | 16 +-
.../server/tablets/UniqueNameAllocator.java | 2 +-
.../accumulo/server/zookeeper/ZooQueueLock.java | 8 +-
.../server/zookeeper/ZooReaderWriter.java | 45 ---
.../zookeeper/ZooReaderWriterFactory.java | 22 --
.../java/org/apache/accumulo/master/Master.java | 4 +-
.../master/tableOps/CancelCompactions.java | 34 +--
.../accumulo/master/tableOps/CompactRange.java | 6 +-
.../master/tableOps/RenameNamespace.java | 2 +-
.../accumulo/master/tableOps/RenameTable.java | 2 +-
.../apache/accumulo/master/tableOps/Utils.java | 12 +-
.../apache/accumulo/master/util/FateAdmin.java | 2 +-
.../org/apache/accumulo/tserver/Tablet.java | 10 +-
28 files changed, 688 insertions(+), 478 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReader.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReader.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReader.java
index 0610e79..610b1bd 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReader.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReader.java
@@ -23,21 +23,23 @@ import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.data.Stat;
public interface IZooReader {
-
+
byte[] getData(String zPath, Stat stat) throws KeeperException, InterruptedException;
-
+
+ byte[] getData(String zPath, boolean watch, Stat stat) throws KeeperException, InterruptedException;
+
Stat getStatus(String zPath) throws KeeperException, InterruptedException;
-
+
Stat getStatus(String zPath, Watcher watcher) throws KeeperException, InterruptedException;
-
+
List<String> getChildren(String zPath) throws KeeperException, InterruptedException;
-
+
List<String> getChildren(String zPath, Watcher watcher) throws KeeperException, InterruptedException;
-
+
boolean exists(String zPath) throws KeeperException, InterruptedException;
-
+
boolean exists(String zPath, Watcher watcher) throws KeeperException, InterruptedException;
-
+
void sync(final String path) throws KeeperException, InterruptedException;
-
+
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
new file mode 100644
index 0000000..4a37172
--- /dev/null
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
@@ -0,0 +1,74 @@
+/*
+ * 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.accumulo.fate.zookeeper;
+
+import org.apache.log4j.Logger;
+
+/**
+ *
+ */
+public class Retry {
+ private static final Logger log = Logger.getLogger(Retry.class);
+
+ private final long maxRetries, maxWait, waitIncrement;
+ private long retriesDone, currentWait;
+
+ /**
+ * @param maxRetries
+ * Maximum times to retry
+ * @param startWait
+ * The amount of time (ms) to wait for the initial retry
+ * @param maxWait
+ * The maximum wait (ms)
+ * @param waitIncrement
+ * The amount of time (ms) to increment next wait time by
+ */
+ public Retry(long maxRetries, long startWait, long maxWait, long waitIncrement) {
+ this.maxRetries = maxRetries;
+ this.maxWait = maxWait;
+ this.waitIncrement = waitIncrement;
+ this.retriesDone = 0l;
+ this.currentWait = startWait;
+ }
+
+ public boolean canRetry() {
+ return retriesDone < maxRetries;
+ }
+
+ public void useRetry() {
+ if (!canRetry()) {
+ throw new IllegalStateException("No retries left");
+ }
+
+ retriesDone++;
+ }
+
+ public boolean hasRetried() {
+ return retriesDone > 0;
+ }
+
+ public long retriesCompleted() {
+ return retriesDone;
+ }
+
+ public void waitForNextAttempt() throws InterruptedException {
+ log.debug("Sleeping for " + currentWait + "ms before retrying operation");
+ Thread.sleep(currentWait);
+ currentWait = Math.min(maxWait, currentWait + waitIncrement);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
new file mode 100644
index 0000000..3fcb738
--- /dev/null
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
@@ -0,0 +1,36 @@
+/*
+ * 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.accumulo.fate.zookeeper;
+
+/**
+ *
+ */
+public class RetryFactory {
+
+ private final long maxRetries, startWait, maxWait, waitIncrement;
+
+ public RetryFactory(long maxRetries, long startWait, long maxWait, long waitIncrement) {
+ this.maxRetries = maxRetries;
+ this.startWait = startWait;
+ this.maxWait = maxWait;
+ this.waitIncrement = waitIncrement;
+ }
+
+ public Retry create() {
+ return new Retry(maxRetries, startWait, maxWait, waitIncrement);
+ }
+}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandler.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandler.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandler.java
deleted file mode 100644
index 4597036..0000000
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandler.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.accumulo.fate.zookeeper;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import org.apache.accumulo.fate.util.UtilWaitThread;
-import org.apache.log4j.Logger;
-import org.apache.zookeeper.KeeperException;
-
-/**
- * An invocation handler for ZooKeeper reader/writers that retries calls that fail due to connection loss.
- */
-public class RetryingInvocationHandler implements InvocationHandler {
- private final IZooReaderWriter zrw;
-
- /**
- * Creates a new invocation handler.
- *
- * @param zrw
- * ZooKeeper reader/writer being handled
- */
- public RetryingInvocationHandler(IZooReaderWriter zrw) {
- this.zrw = zrw;
- }
-
- private static final long INITIAL_RETRY_TIME = 250L;
- private static final long RETRY_INCREMENT = 250L;
- private static final long MAXIMUM_RETRY_TIME = 5000L;
-
- @Override
- public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
- long retryTime = INITIAL_RETRY_TIME;
- while (true) {
- try {
- return method.invoke(zrw, args);
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof KeeperException.ConnectionLossException) {
- Logger.getLogger(ZooReaderWriter.class).warn("Error connecting to zookeeper, will retry in " + String.format("%.2f secs", retryTime / 1000.0), e.getCause());
- UtilWaitThread.sleep(retryTime);
- retryTime = Math.min(MAXIMUM_RETRY_TIME, retryTime + RETRY_INCREMENT);
- } else {
- throw e.getCause();
- }
- }
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooQueueLock.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooQueueLock.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooQueueLock.java
index f30cda3..f9195f3 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooQueueLock.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooQueueLock.java
@@ -29,26 +29,26 @@ import org.apache.zookeeper.KeeperException.NoNodeException;
import org.apache.zookeeper.KeeperException.NotEmptyException;
public class ZooQueueLock implements QueueLock {
-
+
private static final String PREFIX = "lock-";
-
+
// private static final Logger log = Logger.getLogger(ZooQueueLock.class);
-
+
private IZooReaderWriter zoo;
private String path;
private boolean ephemeral;
-
+
public ZooQueueLock(String zookeepers, int timeInMillis, String scheme, byte[] auth, String path, boolean ephemeral) throws KeeperException,
InterruptedException {
- this(ZooReaderWriter.getRetryingInstance(zookeepers, timeInMillis, scheme, auth), path, ephemeral);
+ this(ZooReaderWriter.getInstance(zookeepers, timeInMillis, scheme, auth), path, ephemeral);
}
-
+
protected ZooQueueLock(IZooReaderWriter zrw, String path, boolean ephemeral) {
this.zoo = zrw;
this.path = path;
this.ephemeral = ephemeral;
}
-
+
@Override
public long addEntry(byte[] data) {
String newPath;
@@ -72,7 +72,7 @@ public class ZooQueueLock implements QueueLock {
throw new RuntimeException(ex);
}
}
-
+
@Override
public SortedMap<Long,byte[]> getEarlierEntries(long entry) {
SortedMap<Long,byte[]> result = new TreeMap<Long,byte[]>();
@@ -83,7 +83,7 @@ public class ZooQueueLock implements QueueLock {
} catch (KeeperException.NoNodeException ex) {
// the path does not exist (it was deleted or not created yet), that is ok there are no earlier entries then
}
-
+
for (String name : children) {
// this try catch must be done inside the loop because some subset of the children may exist
try {
@@ -100,7 +100,7 @@ public class ZooQueueLock implements QueueLock {
}
return result;
}
-
+
@Override
public void removeEntry(long entry) {
try {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
index 60660d6..994f395 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
@@ -20,6 +20,7 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.log4j.Logger;
import org.apache.zookeeper.AsyncCallback.VoidCallback;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.Code;
@@ -28,8 +29,11 @@ import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
public class ZooReader implements IZooReader {
+ private static final Logger log = Logger.getLogger(ZooReader.class);
+
protected String keepers;
protected int timeout;
+ protected final RetryFactory retryFactory;
protected ZooKeeper getSession(String keepers, int timeout, String scheme, byte[] auth) {
return ZooSession.getSession(keepers, timeout, scheme, auth);
@@ -39,39 +43,153 @@ public class ZooReader implements IZooReader {
return getSession(keepers, timeout, null, null);
}
+ protected void retryOrThrow(Retry retry, KeeperException e) throws KeeperException {
+ log.warn("Saw (possibly) transient exception communicating with ZooKeeper", e);
+ if (retry.canRetry()) {
+ retry.useRetry();
+ return;
+ }
+
+ log.error("Retry attempts (" + retry.retriesCompleted() + ") exceeded trying to communicate with ZooKeeper");
+ throw e;
+ }
+
@Override
public byte[] getData(String zPath, Stat stat) throws KeeperException, InterruptedException {
- return getZooKeeper().getData(zPath, false, stat);
+ return getData(zPath, false, stat);
+ }
+
+ @Override
+ public byte[] getData(String zPath, boolean watch, Stat stat) throws KeeperException, InterruptedException {
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().getData(zPath, watch, stat);
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
public Stat getStatus(String zPath) throws KeeperException, InterruptedException {
- return getZooKeeper().exists(zPath, false);
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().exists(zPath, false);
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
public Stat getStatus(String zPath, Watcher watcher) throws KeeperException, InterruptedException {
- return getZooKeeper().exists(zPath, watcher);
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().exists(zPath, watcher);
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
public List<String> getChildren(String zPath) throws KeeperException, InterruptedException {
- return getZooKeeper().getChildren(zPath, false);
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().getChildren(zPath, false);
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
public List<String> getChildren(String zPath, Watcher watcher) throws KeeperException, InterruptedException {
- return getZooKeeper().getChildren(zPath, watcher);
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().getChildren(zPath, watcher);
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
public boolean exists(String zPath) throws KeeperException, InterruptedException {
- return getZooKeeper().exists(zPath, false) != null;
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().exists(zPath, false) != null;
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
public boolean exists(String zPath, Watcher watcher) throws KeeperException, InterruptedException {
- return getZooKeeper().exists(zPath, watcher) != null;
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().exists(zPath, watcher) != null;
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
@@ -101,5 +219,6 @@ public class ZooReader implements IZooReader {
public ZooReader(String keepers, int timeout) {
this.keepers = keepers;
this.timeout = timeout;
+ this.retryFactory = new RetryFactory(10l, 250l, 250l, 5000l);
}
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
index 1f0ae14..b29b88a 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
@@ -16,31 +16,29 @@
*/
package org.apache.accumulo.fate.zookeeper;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Proxy;
import java.security.SecurityPermission;
import java.util.Arrays;
import java.util.List;
import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeMissingPolicy;
+import org.apache.log4j.Logger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
-import org.apache.zookeeper.KeeperException.BadVersionException;
-import org.apache.zookeeper.KeeperException.NodeExistsException;
+import org.apache.zookeeper.KeeperException.Code;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
-
+ private static final Logger log = Logger.getLogger(ZooReaderWriter.class);
+
private static SecurityPermission ZOOWRITER_PERMISSION = new SecurityPermission("zookeeperWriterPermission");
-
+
private static ZooReaderWriter instance = null;
- private static IZooReaderWriter retryingInstance = null;
private final String scheme;
private final byte[] auth;
-
+
@Override
public ZooKeeper getZooKeeper() {
SecurityManager sm = System.getSecurityManager();
@@ -49,127 +47,158 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
}
return getSession(keepers, timeout, scheme, auth);
}
-
+
public ZooReaderWriter(String string, int timeInMillis, String scheme, byte[] auth) {
super(string, timeInMillis);
this.scheme = scheme;
this.auth = Arrays.copyOf(auth, auth.length);
}
-
+
@Override
public void recursiveDelete(String zPath, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
ZooUtil.recursiveDelete(getZooKeeper(), zPath, policy);
}
-
+
@Override
public void recursiveDelete(String zPath, int version, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
ZooUtil.recursiveDelete(getZooKeeper(), zPath, version, policy);
}
-
+
/**
* Create a persistent node with the default ACL
- *
+ *
* @return true if the node was created or altered; false if it was skipped
*/
@Override
public boolean putPersistentData(String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
return ZooUtil.putPersistentData(getZooKeeper(), zPath, data, policy);
}
-
+
@Override
public boolean putPrivatePersistentData(String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
return ZooUtil.putPrivatePersistentData(getZooKeeper(), zPath, data, policy);
}
-
+
@Override
public void putPersistentData(String zPath, byte[] data, int version, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
ZooUtil.putPersistentData(getZooKeeper(), zPath, data, version, policy);
}
-
+
@Override
public String putPersistentSequential(String zPath, byte[] data) throws KeeperException, InterruptedException {
return ZooUtil.putPersistentSequential(getZooKeeper(), zPath, data);
}
-
+
@Override
public String putEphemeralData(String zPath, byte[] data) throws KeeperException, InterruptedException {
return ZooUtil.putEphemeralData(getZooKeeper(), zPath, data);
}
-
+
@Override
public String putEphemeralSequential(String zPath, byte[] data) throws KeeperException, InterruptedException {
return ZooUtil.putEphemeralSequential(getZooKeeper(), zPath, data);
}
-
+
@Override
public void recursiveCopyPersistent(String source, String destination, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
ZooUtil.recursiveCopyPersistent(getZooKeeper(), source, destination, policy);
}
-
+
@Override
public void delete(String path, int version) throws InterruptedException, KeeperException {
- getZooKeeper().delete(path, version);
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ getZooKeeper().delete(path, version);
+ return;
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.NONODE) {
+ if (retry.hasRetried()) {
+ // A retried delete could have deleted the node, assume that was the case
+ log.debug("Delete saw no node on a retry. Assuming node was deleted");
+ return;
+ }
+
+ throw e;
+ } else if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ // retry if we have more attempts to do so
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
-
+
@Override
public byte[] mutate(String zPath, byte[] createValue, List<ACL> acl, Mutator mutator) throws Exception {
if (createValue != null) {
- try {
- getZooKeeper().create(zPath, createValue, acl, CreateMode.PERSISTENT);
- return createValue;
- } catch (NodeExistsException ex) {
- // expected
+ while (true) {
+ final Retry retry = retryFactory.create();
+ try {
+ getZooKeeper().create(zPath, createValue, acl, CreateMode.PERSISTENT);
+ return createValue;
+ } catch (KeeperException ex) {
+ final Code code = ex.code();
+ if (code == Code.NODEEXISTS) {
+ // expected
+ break;
+ } else if (code == Code.OPERATIONTIMEOUT || code == Code.CONNECTIONLOSS || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, ex);
+ } else {
+ throw ex;
+ }
+ }
+
+ retry.waitForNextAttempt();
}
}
do {
+ final Retry retry = retryFactory.create();
Stat stat = new Stat();
- byte[] data = getZooKeeper().getData(zPath, false, stat);
+ byte[] data = getData(zPath, false, stat);
data = mutator.mutate(data);
if (data == null)
return data;
try {
getZooKeeper().setData(zPath, data, stat.getVersion());
return data;
- } catch (BadVersionException ex) {
- //
+ } catch (KeeperException ex) {
+ final Code code = ex.code();
+ if (code == Code.BADVERSION) {
+ // Retry, but don't increment. This makes it backwards compatible with the infinite
+ // loop that previously happened. I'm not sure if that's really desirable though.
+ } else if (code == Code.OPERATIONTIMEOUT || code == Code.CONNECTIONLOSS || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, ex);
+ retry.waitForNextAttempt();
+ } else {
+ throw ex;
+ }
}
} while (true);
}
-
+
public static synchronized ZooReaderWriter getInstance(String zookeepers, int timeInMillis, String scheme, byte[] auth) {
if (instance == null)
instance = new ZooReaderWriter(zookeepers, timeInMillis, scheme, auth);
return instance;
}
-
- /**
- * get an instance that retries when zookeeper connection errors occur
- *
- * @return an instance that retries when Zookeeper connection errors occur.
- */
- public static synchronized IZooReaderWriter getRetryingInstance(String zookeepers, int timeInMillis, String scheme, byte[] auth) {
-
- if (retryingInstance == null) {
- IZooReaderWriter inst = getInstance(zookeepers, timeInMillis, scheme, auth);
- InvocationHandler ih = new RetryingInvocationHandler(inst);
- retryingInstance = (IZooReaderWriter) Proxy.newProxyInstance(ZooReaderWriter.class.getClassLoader(), new Class[] {IZooReaderWriter.class}, ih);
- }
-
- return retryingInstance;
- }
-
+
@Override
public boolean isLockHeld(ZooUtil.LockID lockID) throws KeeperException, InterruptedException {
return ZooUtil.isLockHeld(getZooKeeper(), lockID);
}
-
+
@Override
public void mkdirs(String path) throws KeeperException, InterruptedException {
if (path.equals(""))
return;
if (!path.startsWith("/"))
throw new IllegalArgumentException(path + "does not start with /");
- if (getZooKeeper().exists(path, false) != null)
+ if (exists(path))
return;
String parent = path.substring(0, path.lastIndexOf("/"));
mkdirs(parent);
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooSession.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooSession.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooSession.java
index 33bd77b..b6890c6 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooSession.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooSession.java
@@ -33,7 +33,7 @@ import org.apache.zookeeper.ZooKeeper.States;
public class ZooSession {
private static final Charset UTF8 = Charset.forName("UTF-8");
-
+
public static class ZooSessionShutdownException extends RuntimeException {
private static final long serialVersionUID = 1L;
@@ -41,31 +41,32 @@ public class ZooSession {
}
private static final Logger log = Logger.getLogger(ZooSession.class);
-
+
private static class ZooSessionInfo {
public ZooSessionInfo(ZooKeeper zooKeeper, ZooWatcher watcher) {
this.zooKeeper = zooKeeper;
}
-
+
ZooKeeper zooKeeper;
}
-
+
private static Map<String,ZooSessionInfo> sessions = new HashMap<String,ZooSessionInfo>();
-
+
private static String sessionKey(String keepers, int timeout, String scheme, byte[] auth) {
return keepers + ":" + timeout + ":" + (scheme == null ? "" : scheme) + ":" + (auth == null ? "" : new String(auth, UTF8));
}
-
+
private static class ZooWatcher implements Watcher {
-
+
+ @Override
public void process(WatchedEvent event) {
if (event.getState() == KeeperState.Expired) {
log.debug("Session expired, state of current session : " + event.getState());
}
}
-
+
}
-
+
/**
* @param host comma separated list of zk servers
* @param timeout in milliseconds
@@ -79,9 +80,9 @@ public class ZooSession {
boolean tryAgain = true;
long sleepTime = 100;
ZooKeeper zooKeeper = null;
-
+
long startTime = System.currentTimeMillis();
-
+
while (tryAgain) {
try {
zooKeeper = new ZooKeeper(host, timeout, watcher);
@@ -94,7 +95,7 @@ public class ZooSession {
} else
UtilWaitThread.sleep(TIME_BETWEEN_CONNECT_CHECKS_MS);
}
-
+
} catch (IOException e) {
if (e instanceof UnknownHostException) {
/*
@@ -116,13 +117,13 @@ public class ZooSession {
if (System.currentTimeMillis() - startTime > 2 * timeout) {
throw new RuntimeException("Failed to connect to zookeeper (" + host + ") within 2x zookeeper timeout period " + timeout);
}
-
+
if (tryAgain) {
if (startTime + 2 * timeout < System.currentTimeMillis() + sleepTime + connectTimeWait)
sleepTime = startTime + 2 * timeout - System.currentTimeMillis() - connectTimeWait;
if (sleepTime < 0)
{
- connectTimeWait -= sleepTime;
+ connectTimeWait -= sleepTime;
sleepTime = 0;
}
UtilWaitThread.sleep(sleepTime);
@@ -130,31 +131,32 @@ public class ZooSession {
sleepTime = sleepTime + (long)(sleepTime * Math.random());
}
}
-
+
return zooKeeper;
}
-
+
public static synchronized ZooKeeper getSession(String zooKeepers, int timeout) {
return getSession(zooKeepers, timeout, null, null);
}
-
+
public static synchronized ZooKeeper getSession(String zooKeepers, int timeout, String scheme, byte[] auth) {
-
+
if (sessions == null)
throw new ZooSessionShutdownException();
String sessionKey = sessionKey(zooKeepers, timeout, scheme, auth);
-
+
// a read-only session can use a session with authorizations, so cache a copy for it w/out auths
String readOnlySessionKey = sessionKey(zooKeepers, timeout, null, null);
ZooSessionInfo zsi = sessions.get(sessionKey);
if (zsi != null && zsi.zooKeeper.getState() == States.CLOSED) {
+ log.debug("Removing closed ZooKeeper session to " + zooKeepers);
if (auth != null && sessions.get(readOnlySessionKey) == zsi)
sessions.remove(readOnlySessionKey);
zsi = null;
sessions.remove(sessionKey);
}
-
+
if (zsi == null) {
ZooWatcher watcher = new ZooWatcher();
log.debug("Connecting to " + zooKeepers + " with timeout " + timeout + " with auth");
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
index 5b856c0..e0d8831 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
@@ -21,12 +21,11 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import org.apache.accumulo.fate.util.UtilWaitThread;
+import org.apache.log4j.Logger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.Code;
import org.apache.zookeeper.KeeperException.NoNodeException;
-import org.apache.zookeeper.KeeperException.NodeExistsException;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooDefs.Perms;
import org.apache.zookeeper.ZooKeeper;
@@ -34,27 +33,29 @@ import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
public class ZooUtil {
+ private static final Logger log = Logger.getLogger(ZooUtil.class);
+
public enum NodeExistsPolicy {
SKIP, OVERWRITE, FAIL
}
-
+
public enum NodeMissingPolicy {
SKIP, CREATE, FAIL
}
-
+
public static class LockID {
public long eid;
public String path;
public String node;
-
+
public LockID(String root, String serializedLID) {
String sa[] = serializedLID.split("\\$");
int lastSlash = sa[0].lastIndexOf('/');
-
+
if (sa.length != 2 || lastSlash < 0) {
throw new IllegalArgumentException("Malformed serialized lock id " + serializedLID);
}
-
+
if (lastSlash == 0)
path = root;
else
@@ -62,37 +63,50 @@ public class ZooUtil {
node = sa[0].substring(lastSlash + 1);
eid = new BigInteger(sa[1], 16).longValue();
}
-
+
public LockID(String path, String node, long eid) {
this.path = path;
this.node = node;
this.eid = eid;
}
-
+
public String serialize(String root) {
-
+
return path.substring(root.length()) + "/" + node + "$" + Long.toHexString(eid);
}
-
+
@Override
public String toString() {
return " path = " + path + " node = " + node + " eid = " + Long.toHexString(eid);
}
}
-
+
public static final List<ACL> PRIVATE;
public static final List<ACL> PUBLIC;
+ private static final RetryFactory RETRY_FACTORY;
static {
PRIVATE = new ArrayList<ACL>();
PRIVATE.addAll(Ids.CREATOR_ALL_ACL);
PUBLIC = new ArrayList<ACL>();
PUBLIC.addAll(PRIVATE);
PUBLIC.add(new ACL(Perms.READ, Ids.ANYONE_ID_UNSAFE));
+ RETRY_FACTORY = new RetryFactory(10l, 250l, 250l, 5000l);
}
-
+
+ protected static void retryOrThrow(Retry retry, KeeperException e) throws KeeperException {
+ log.warn("Saw (possibly) transient exception communicating with ZooKeeper", e);
+ if (retry.canRetry()) {
+ retry.useRetry();
+ return;
+ }
+
+ log.error("Retry attempts (" + retry.retriesCompleted() + ") exceeded trying to communicate with ZooKeeper");
+ throw e;
+ }
+
/**
* This method will delete a node and all its children from zookeeper
- *
+ *
* @param zPath
* the path to delete
*/
@@ -100,82 +114,180 @@ public class ZooUtil {
if (policy.equals(NodeMissingPolicy.CREATE))
throw new IllegalArgumentException(policy.name() + " is invalid for this operation");
try {
- for (String child : zk.getChildren(zPath, false))
+ List<String> children;
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ children = zk.getChildren(zPath, false);
+ break;
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+ retry.waitForNextAttempt();
+ }
+ for (String child : children)
recursiveDelete(zk, zPath + "/" + child, NodeMissingPolicy.SKIP);
-
+
Stat stat;
- if ((stat = zk.exists(zPath, null)) != null)
- zk.delete(zPath, stat.getVersion());
+ while (true) {
+ try {
+ stat = zk.exists(zPath, null);
+ // Node exists
+ if (stat != null) {
+ try {
+ // Try to delete it
+ zk.delete(zPath, stat.getVersion());
+ return;
+ } catch (NoNodeException e) {
+ // If the node is gone now, it's ok if we have SKIP
+ if (policy.equals(NodeMissingPolicy.SKIP)) {
+ return;
+ }
+ throw e;
+ }
+ // Let other KeeperException bubble to the outer catch
+ }
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
} catch (KeeperException e) {
if (policy.equals(NodeMissingPolicy.SKIP) && e.code().equals(KeeperException.Code.NONODE))
return;
throw e;
}
}
-
+
public static void recursiveDelete(ZooKeeper zk, String zPath, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
recursiveDelete(zk, zPath, -1, policy);
}
-
+
/**
* Create a persistent node with the default ACL
- *
+ *
* @return true if the node was created or altered; false if it was skipped
*/
public static boolean putPersistentData(ZooKeeper zk, String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
return putData(zk, zPath, data, CreateMode.PERSISTENT, -1, policy, PUBLIC);
}
-
+
public static boolean putPersistentData(ZooKeeper zk, String zPath, byte[] data, int version, NodeExistsPolicy policy) throws KeeperException,
InterruptedException {
return putData(zk, zPath, data, CreateMode.PERSISTENT, version, policy, PUBLIC);
}
-
+
public static boolean putPersistentData(ZooKeeper zk, String zPath, byte[] data, int version, NodeExistsPolicy policy, List<ACL> acls)
throws KeeperException, InterruptedException {
return putData(zk, zPath, data, CreateMode.PERSISTENT, version, policy, acls);
}
-
+
private static boolean putData(ZooKeeper zk, String zPath, byte[] data, CreateMode mode, int version, NodeExistsPolicy policy, List<ACL> acls)
throws KeeperException, InterruptedException {
if (policy == null)
policy = NodeExistsPolicy.FAIL;
-
+
+ final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
zk.create(zPath, data, acls, mode);
return true;
- } catch (NodeExistsException nee) {
- switch (policy) {
- case SKIP:
- return false;
- case OVERWRITE:
- try {
- zk.setData(zPath, data, version);
- return true;
- } catch (NoNodeException nne) {
- // node delete between create call and set data, so try create call again
- continue;
- }
- default:
- throw nee;
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.NODEEXISTS) {
+ switch (policy) {
+ case SKIP:
+ return false;
+ case OVERWRITE:
+ // overwrite the data in the node when it already exists
+ try {
+ zk.setData(zPath, data, version);
+ return true;
+ } catch (KeeperException e2) {
+ final Code code2 = e2.code();
+ if (code2 == Code.NONODE) {
+ // node delete between create call and set data, so try create call again
+ continue;
+ } else if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ // unhandled exception on setData()
+ throw e;
+ }
+ }
+ default:
+ throw e;
+ }
+ } else if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ // unhandled exception on create()
+ throw e;
}
}
+
+ // Catch all to wait before retrying
+ retry.waitForNextAttempt();
}
}
-
+
public static byte[] getData(ZooKeeper zk, String zPath, Stat stat) throws KeeperException, InterruptedException {
- return zk.getData(zPath, false, stat);
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ return zk.getData(zPath, false, stat);
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
-
+
public static Stat getStatus(ZooKeeper zk, String zPath) throws KeeperException, InterruptedException {
- return zk.exists(zPath, false);
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ return zk.exists(zPath, false);
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
-
+
public static boolean exists(ZooKeeper zk, String zPath) throws KeeperException, InterruptedException {
return getStatus(zk, zPath) != null;
}
-
+
public static void recursiveCopyPersistent(ZooKeeper zk, String source, String destination, NodeExistsPolicy policy) throws KeeperException,
InterruptedException {
Stat stat = null;
@@ -192,9 +304,10 @@ public class ZooUtil {
throw KeeperException.create(Code.NODEEXISTS, source);
}
}
-
+
stat = new Stat();
- byte[] data = zk.getData(source, false, stat);
+ byte[] data = getData(zk, source, stat);
+
if (stat.getEphemeralOwner() == 0) {
if (data == null)
throw KeeperException.create(Code.NONODE, source);
@@ -204,61 +317,113 @@ public class ZooUtil {
recursiveCopyPersistent(zk, source + "/" + child, destination + "/" + child, policy);
}
}
-
+
public static boolean putPrivatePersistentData(ZooKeeper zk, String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
return putData(zk, zPath, data, CreateMode.PERSISTENT, -1, policy, PRIVATE);
}
-
+
public static String putPersistentSequential(ZooKeeper zk, String zPath, byte[] data) throws KeeperException, InterruptedException {
- return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.PERSISTENT_SEQUENTIAL);
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.PERSISTENT_SEQUENTIAL);
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
-
+
public static String putEphemeralData(ZooKeeper zk, String zPath, byte[] data) throws KeeperException, InterruptedException {
- return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL);
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL);
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
public static String putEphemeralSequential(ZooKeeper zk, String zPath, byte[] data) throws KeeperException, InterruptedException {
- return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL_SEQUENTIAL);
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL_SEQUENTIAL);
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
-
+
public static byte[] getLockData(ZooCache zc, String path) {
-
+
List<String> children = zc.getChildren(path);
-
+
if (children == null || children.size() == 0) {
return null;
}
-
+
children = new ArrayList<String>(children);
Collections.sort(children);
-
+
String lockNode = children.get(0);
-
+
return zc.get(path + "/" + lockNode);
}
-
+
public static boolean isLockHeld(ZooKeeper zk, LockID lid) throws KeeperException, InterruptedException {
-
+ final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
+ // TODO push down retry to getChildren and exists
List<String> children = zk.getChildren(lid.path, false);
-
+
if (children.size() == 0) {
return false;
}
-
+
Collections.sort(children);
-
+
String lockNode = children.get(0);
if (!lid.node.equals(lockNode))
return false;
-
+
Stat stat = zk.exists(lid.path + "/" + lid.node, false);
return stat != null && stat.getEphemeralOwner() == lid.eid;
- } catch (KeeperException.ConnectionLossException ex) {
- UtilWaitThread.sleep(1000);
+ } catch (KeeperException ex) {
+ final Code c = ex.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, ex);
+ }
}
+
+ retry.waitForNextAttempt();
}
}
-
+
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandlerTest.java
----------------------------------------------------------------------
diff --git a/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandlerTest.java b/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandlerTest.java
deleted file mode 100644
index 0613a1f..0000000
--- a/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandlerTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.accumulo.fate.zookeeper;
-
-import java.lang.reflect.Method;
-import org.apache.zookeeper.KeeperException.ConnectionLossException;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-import static org.easymock.EasyMock.aryEq;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
-
-public class RetryingInvocationHandlerTest {
- private static final String PATH = "/path/to/somewhere";
- private static final byte[] DATA = {(byte) 1, (byte) 2};
- private static final Object[] ARGS = {PATH, DATA};
- private static final String RV = "OK";
-
- private static Method putMethod;
-
- @BeforeClass
- public static void setUpClass() throws Exception {
- putMethod = IZooReaderWriter.class.getMethod("putEphemeralData", String.class, byte[].class);
- }
-
- private IZooReaderWriter zrw;
- private RetryingInvocationHandler ih;
-
- @Before
- public void setUp() throws Exception {
- zrw = createMock(IZooReaderWriter.class);
- ih = new RetryingInvocationHandler(zrw);
- }
-
- @Test
- public void testInvokeSuccessful() throws Throwable {
- expect(zrw.putEphemeralData(eq(PATH), aryEq(DATA))).andReturn(RV);
- replay(zrw);
- Object rv = ih.invoke(null, putMethod, ARGS);
- verify(zrw);
- assertEquals(RV, rv);
- }
-
- @Test
- public void testInvokeRetrySuccessful() throws Throwable {
- ConnectionLossException e = createMock(ConnectionLossException.class);
- expect(zrw.putEphemeralData(eq(PATH), aryEq(DATA))).andThrow(e);
- expect(zrw.putEphemeralData(eq(PATH), aryEq(DATA))).andThrow(e);
- expect(zrw.putEphemeralData(eq(PATH), aryEq(DATA))).andReturn(RV);
- replay(zrw);
- Object rv = ih.invoke(null, putMethod, ARGS);
- verify(zrw);
- assertEquals(RV, rv);
- }
-
- @Test(expected = InterruptedException.class)
- public void testInvokeRetryFailure() throws Throwable {
- ConnectionLossException e = createMock(ConnectionLossException.class);
- expect(zrw.putEphemeralData(eq(PATH), aryEq(DATA))).andThrow(e);
- expect(zrw.putEphemeralData(eq(PATH), aryEq(DATA))).andThrow(new InterruptedException());
- replay(zrw);
- try {
- ih.invoke(null, putMethod, ARGS);
- } finally {
- verify(zrw);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/Accumulo.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/Accumulo.java b/server/base/src/main/java/org/apache/accumulo/server/Accumulo.java
index ca70efe..6ba05cc 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/Accumulo.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/Accumulo.java
@@ -301,7 +301,7 @@ public class Accumulo {
public static void abortIfFateTransactions() {
try {
final ReadOnlyTStore<Accumulo> fate = new ReadOnlyStore<Accumulo>(new ZooStore<Accumulo>(ZooUtil.getRoot(HdfsZooInstance.getInstance()) + Constants.ZFATE,
- ZooReaderWriter.getRetryingInstance()));
+ ZooReaderWriter.getInstance()));
if (!(fate.list().isEmpty())) {
throw new AccumuloException("Aborting upgrade because there are outstanding FATE transactions from a previous Accumulo version. Please see the README document for instructions on what to do under your previous version.");
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java b/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
index 63bd894..e8d5bbf 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
@@ -388,7 +388,7 @@ public class LiveTServerSet implements Watcher {
log.info("Removing zookeeper lock for " + server);
String fullpath = ZooUtil.getRoot(instance) + Constants.ZTSERVERS + "/" + zPath;
try {
- ZooReaderWriter.getRetryingInstance().recursiveDelete(fullpath, SKIP);
+ ZooReaderWriter.getInstance().recursiveDelete(fullpath, SKIP);
} catch (Exception e) {
String msg = "error removing tablet server lock";
log.fatal(msg, e);
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
index 1646a28..5f6ff71 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
@@ -39,40 +39,40 @@ import org.apache.zookeeper.KeeperException;
public final class ZKAuthenticator implements Authenticator {
static final Logger log = Logger.getLogger(ZKAuthenticator.class);
private static Authenticator zkAuthenticatorInstance = null;
-
+
private String ZKUserPath;
private final ZooCache zooCache;
-
+
public static synchronized Authenticator getInstance() {
if (zkAuthenticatorInstance == null)
zkAuthenticatorInstance = new ZKAuthenticator();
return zkAuthenticatorInstance;
}
-
+
public ZKAuthenticator() {
zooCache = new ZooCache();
}
-
+
@Override
public void initialize(String instanceId, boolean initialize) {
ZKUserPath = Constants.ZROOT + "/" + instanceId + "/users";
}
-
+
@Override
public void initializeSecurity(TCredentials credentials, String principal, byte[] token) throws AccumuloSecurityException {
try {
// remove old settings from zookeeper first, if any
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
synchronized (zooCache) {
zooCache.clear();
if (zoo.exists(ZKUserPath)) {
zoo.recursiveDelete(ZKUserPath, NodeMissingPolicy.SKIP);
log.info("Removed " + ZKUserPath + "/" + " from zookeeper");
}
-
+
// prep parent node of users with root username
zoo.putPersistentData(ZKUserPath, principal.getBytes(Constants.UTF8), NodeExistsPolicy.FAIL);
-
+
constructUser(principal, ZKSecurityTool.createPass(token));
}
} catch (KeeperException e) {
@@ -86,23 +86,23 @@ public final class ZKAuthenticator implements Authenticator {
throw new RuntimeException(e);
}
}
-
+
/**
* Sets up the user in ZK for the provided user. No checking for existence is done here, it should be done before calling.
*/
private void constructUser(String user, byte[] pass) throws KeeperException, InterruptedException {
synchronized (zooCache) {
zooCache.clear();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.putPrivatePersistentData(ZKUserPath + "/" + user, pass, NodeExistsPolicy.FAIL);
}
}
-
+
@Override
public Set<String> listUsers() {
return new TreeSet<String>(zooCache.getChildren(ZKUserPath));
}
-
+
/**
* Creates a user with no permissions whatsoever
*/
@@ -125,13 +125,13 @@ public final class ZKAuthenticator implements Authenticator {
throw new AccumuloSecurityException(principal, SecurityErrorCode.DEFAULT_SECURITY_ERROR, e);
}
}
-
+
@Override
public void dropUser(String user) throws AccumuloSecurityException {
try {
synchronized (zooCache) {
zooCache.clear();
- ZooReaderWriter.getRetryingInstance().recursiveDelete(ZKUserPath + "/" + user, NodeMissingPolicy.FAIL);
+ ZooReaderWriter.getInstance().recursiveDelete(ZKUserPath + "/" + user, NodeMissingPolicy.FAIL);
}
} catch (InterruptedException e) {
log.error(e, e);
@@ -143,7 +143,7 @@ public final class ZKAuthenticator implements Authenticator {
throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
}
}
-
+
@Override
public void changePassword(String principal, AuthenticationToken token) throws AccumuloSecurityException {
if (!(token instanceof PasswordToken))
@@ -153,7 +153,7 @@ public final class ZKAuthenticator implements Authenticator {
try {
synchronized (zooCache) {
zooCache.clear(ZKUserPath + "/" + principal);
- ZooReaderWriter.getRetryingInstance().putPrivatePersistentData(ZKUserPath + "/" + principal, ZKSecurityTool.createPass(pt.getPassword()),
+ ZooReaderWriter.getInstance().putPrivatePersistentData(ZKUserPath + "/" + principal, ZKSecurityTool.createPass(pt.getPassword()),
NodeExistsPolicy.OVERWRITE);
}
} catch (KeeperException e) {
@@ -169,7 +169,7 @@ public final class ZKAuthenticator implements Authenticator {
} else
throw new AccumuloSecurityException(principal, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
}
-
+
/**
* Checks if a user exists
*/
@@ -177,12 +177,12 @@ public final class ZKAuthenticator implements Authenticator {
public boolean userExists(String user) {
return zooCache.get(ZKUserPath + "/" + user) != null;
}
-
+
@Override
public boolean validSecurityHandlers(Authorizor auth, PermissionHandler pm) {
return true;
}
-
+
@Override
public boolean authenticateUser(String principal, AuthenticationToken token) throws AccumuloSecurityException {
if (!(token instanceof PasswordToken))
@@ -199,14 +199,14 @@ public final class ZKAuthenticator implements Authenticator {
}
return result;
}
-
+
@Override
public Set<Class<? extends AuthenticationToken>> getSupportedTokenTypes() {
Set<Class<? extends AuthenticationToken>> cs = new HashSet<Class<? extends AuthenticationToken>>();
cs.add(PasswordToken.class);
return cs;
}
-
+
@Override
public boolean validTokenClass(String tokenClass) {
return tokenClass.equals(PasswordToken.class.getName());
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
index bbaf592..75b73fc 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
@@ -81,7 +81,7 @@ public class ZKAuthorizor implements Authorizor {
@Override
public void initializeSecurity(TCredentials itw, String rootuser) throws AccumuloSecurityException {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
// create the root user with all system privileges, no table privileges, and no record-level authorizations
Set<SystemPermission> rootPerms = new TreeSet<SystemPermission>();
@@ -110,7 +110,7 @@ public class ZKAuthorizor implements Authorizor {
@Override
public void initUser(String user) throws AccumuloSecurityException {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
try {
zoo.putPersistentData(ZKUserPath + "/" + user, new byte[0], NodeExistsPolicy.SKIP);
} catch (KeeperException e) {
@@ -126,7 +126,7 @@ public class ZKAuthorizor implements Authorizor {
public void dropUser(String user) throws AccumuloSecurityException {
try {
synchronized (zooCache) {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserAuths, NodeMissingPolicy.SKIP);
zooCache.clear(ZKUserPath + "/" + user);
}
@@ -147,7 +147,7 @@ public class ZKAuthorizor implements Authorizor {
try {
synchronized (zooCache) {
zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserAuths, ZKSecurityTool.convertAuthorizations(authorizations),
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserAuths, ZKSecurityTool.convertAuthorizations(authorizations),
NodeExistsPolicy.OVERWRITE);
}
} catch (KeeperException e) {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
index 1b7e7d3..3cac2e9 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
@@ -81,14 +81,14 @@ public class ZKPermHandler implements PermissionHandler {
byte[] serializedPerms;
try {
String path = ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table;
- ZooReaderWriter.getRetryingInstance().sync(path);
- serializedPerms = ZooReaderWriter.getRetryingInstance().getData(path, null);
+ ZooReaderWriter.getInstance().sync(path);
+ serializedPerms = ZooReaderWriter.getInstance().getData(path, null);
} catch (KeeperException e) {
if (e.code() == Code.NONODE) {
// maybe the table was just deleted?
try {
// check for existence:
- ZooReaderWriter.getRetryingInstance().getData(ZKTablePath + "/" + table, null);
+ ZooReaderWriter.getInstance().getData(ZKTablePath + "/" + table, null);
// it's there, you don't have permission
return false;
} catch (InterruptedException ex) {
@@ -129,14 +129,14 @@ public class ZKPermHandler implements PermissionHandler {
byte[] serializedPerms;
try {
String path = ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace;
- ZooReaderWriter.getRetryingInstance().sync(path);
- serializedPerms = ZooReaderWriter.getRetryingInstance().getData(path, null);
+ ZooReaderWriter.getInstance().sync(path);
+ serializedPerms = ZooReaderWriter.getInstance().getData(path, null);
} catch (KeeperException e) {
if (e.code() == Code.NONODE) {
// maybe the namespace was just deleted?
try {
// check for existence:
- ZooReaderWriter.getRetryingInstance().getData(ZKNamespacePath + "/" + namespace, null);
+ ZooReaderWriter.getInstance().getData(ZKNamespacePath + "/" + namespace, null);
// it's there, you don't have permission
return false;
} catch (InterruptedException ex) {
@@ -187,7 +187,7 @@ public class ZKPermHandler implements PermissionHandler {
if (perms.add(permission)) {
synchronized (zooCache) {
zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(perms),
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(perms),
NodeExistsPolicy.OVERWRITE);
}
}
@@ -213,7 +213,7 @@ public class ZKPermHandler implements PermissionHandler {
if (tablePerms.add(permission)) {
synchronized (zooCache) {
zooCache.clear(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, ZKSecurityTool.convertTablePermissions(tablePerms),
NodeExistsPolicy.OVERWRITE);
}
@@ -240,7 +240,7 @@ public class ZKPermHandler implements PermissionHandler {
if (namespacePerms.add(permission)) {
synchronized (zooCache) {
zooCache.clear(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace);
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace, ZKSecurityTool.convertNamespacePermissions(namespacePerms),
NodeExistsPolicy.OVERWRITE);
}
@@ -268,7 +268,7 @@ public class ZKPermHandler implements PermissionHandler {
if (sysPerms.remove(permission)) {
synchronized (zooCache) {
zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(sysPerms),
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(sysPerms),
NodeExistsPolicy.OVERWRITE);
}
}
@@ -293,7 +293,7 @@ public class ZKPermHandler implements PermissionHandler {
try {
if (tablePerms.remove(permission)) {
zooCache.clear();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
if (tablePerms.size() == 0)
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, NodeMissingPolicy.SKIP);
else
@@ -321,7 +321,7 @@ public class ZKPermHandler implements PermissionHandler {
try {
if (namespacePerms.remove(permission)) {
zooCache.clear();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
if (namespacePerms.size() == 0)
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace, NodeMissingPolicy.SKIP);
else
@@ -342,7 +342,7 @@ public class ZKPermHandler implements PermissionHandler {
try {
synchronized (zooCache) {
zooCache.clear();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
for (String user : zooCache.getChildren(ZKUserPath))
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, NodeMissingPolicy.SKIP);
}
@@ -360,7 +360,7 @@ public class ZKPermHandler implements PermissionHandler {
try {
synchronized (zooCache) {
zooCache.clear();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
for (String user : zooCache.getChildren(ZKUserPath))
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace, NodeMissingPolicy.SKIP);
}
@@ -375,7 +375,7 @@ public class ZKPermHandler implements PermissionHandler {
@Override
public void initializeSecurity(TCredentials itw, String rootuser) throws AccumuloSecurityException {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
// create the root user with all system privileges, no table privileges, and no record-level authorizations
Set<SystemPermission> rootPerms = new TreeSet<SystemPermission>();
@@ -412,7 +412,7 @@ public class ZKPermHandler implements PermissionHandler {
@Override
public void initUser(String user) throws AccumuloSecurityException {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
try {
zoo.putPersistentData(ZKUserPath + "/" + user, new byte[0], NodeExistsPolicy.SKIP);
zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms, new byte[0], NodeExistsPolicy.SKIP);
@@ -432,7 +432,7 @@ public class ZKPermHandler implements PermissionHandler {
private void createTablePerm(String user, String table, Set<TablePermission> perms) throws KeeperException, InterruptedException {
synchronized (zooCache) {
zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table,
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table,
ZKSecurityTool.convertTablePermissions(perms), NodeExistsPolicy.FAIL);
}
}
@@ -443,7 +443,7 @@ public class ZKPermHandler implements PermissionHandler {
private void createNamespacePerm(String user, String namespace, Set<NamespacePermission> perms) throws KeeperException, InterruptedException {
synchronized (zooCache) {
zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace,
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace,
ZKSecurityTool.convertNamespacePermissions(perms), NodeExistsPolicy.FAIL);
}
}
@@ -452,7 +452,7 @@ public class ZKPermHandler implements PermissionHandler {
public void cleanUser(String user) throws AccumuloSecurityException {
try {
synchronized (zooCache) {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserSysPerms, NodeMissingPolicy.SKIP);
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms, NodeMissingPolicy.SKIP);
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserNamespacePerms, NodeMissingPolicy.SKIP);
@@ -475,8 +475,8 @@ public class ZKPermHandler implements PermissionHandler {
byte[] perms;
try {
String path = ZKUserPath + "/" + user + ZKUserSysPerms;
- ZooReaderWriter.getRetryingInstance().sync(path);
- perms = ZooReaderWriter.getRetryingInstance().getData(path, null);
+ ZooReaderWriter.getInstance().sync(path);
+ perms = ZooReaderWriter.getInstance().getData(path, null);
} catch (KeeperException e) {
if (e.code() == Code.NONODE) {
return false;
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java b/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
index 7a61eb6..71b7155 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
@@ -63,7 +63,7 @@ public class TableManager {
log.debug("Creating ZooKeeper entries for new namespace " + namespace + " (ID: " + namespaceId + ")");
String zPath = Constants.ZROOT + "/" + instanceId + Constants.ZNAMESPACES + "/" + namespaceId;
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.putPersistentData(zPath, new byte[0], existsPolicy);
zoo.putPersistentData(zPath + Constants.ZNAMESPACE_NAME, namespace.getBytes(Constants.UTF8), existsPolicy);
zoo.putPersistentData(zPath + Constants.ZNAMESPACE_CONF, new byte[0], existsPolicy);
@@ -76,7 +76,7 @@ public class TableManager {
Pair<String,String> qualifiedTableName = Tables.qualify(tableName);
tableName = qualifiedTableName.getSecond();
String zTablePath = Constants.ZROOT + "/" + instanceId + Constants.ZTABLES + "/" + tableId;
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.putPersistentData(zTablePath, new byte[0], existsPolicy);
zoo.putPersistentData(zTablePath + Constants.ZTABLE_CONF, new byte[0], existsPolicy);
zoo.putPersistentData(zTablePath + Constants.ZTABLE_NAMESPACE, namespaceId.getBytes(Constants.UTF8), existsPolicy);
@@ -132,7 +132,7 @@ public class TableManager {
String statePath = ZooUtil.getRoot(HdfsZooInstance.getInstance()) + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_STATE;
try {
- ZooReaderWriter.getRetryingInstance().mutate(statePath, newState.name().getBytes(Constants.UTF8), ZooUtil.PUBLIC, new Mutator() {
+ ZooReaderWriter.getInstance().mutate(statePath, newState.name().getBytes(Constants.UTF8), ZooUtil.PUBLIC, new Mutator() {
@Override
public byte[] mutate(byte[] oldData) throws Exception {
TableState oldState = TableState.UNKNOWN;
@@ -205,13 +205,13 @@ public class TableManager {
String srcTablePath = Constants.ZROOT + "/" + instance.getInstanceID() + Constants.ZTABLES + "/" + srcTable + Constants.ZTABLE_CONF;
String newTablePath = Constants.ZROOT + "/" + instance.getInstanceID() + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_CONF;
- ZooReaderWriter.getRetryingInstance().recursiveCopyPersistent(srcTablePath, newTablePath, NodeExistsPolicy.OVERWRITE);
+ ZooReaderWriter.getInstance().recursiveCopyPersistent(srcTablePath, newTablePath, NodeExistsPolicy.OVERWRITE);
for (Entry<String,String> entry : propertiesToSet.entrySet())
TablePropUtil.setTableProperty(tableId, entry.getKey(), entry.getValue());
for (String prop : propertiesToExclude)
- ZooReaderWriter.getRetryingInstance().recursiveDelete(
+ ZooReaderWriter.getInstance().recursiveDelete(
Constants.ZROOT + "/" + instance.getInstanceID() + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_CONF + "/" + prop, NodeMissingPolicy.SKIP);
updateTableStateCache(tableId);
@@ -220,9 +220,9 @@ public class TableManager {
public void removeTable(String tableId) throws KeeperException, InterruptedException {
synchronized (tableStateCache) {
tableStateCache.remove(tableId);
- ZooReaderWriter.getRetryingInstance().recursiveDelete(ZooUtil.getRoot(instance) + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_STATE,
+ ZooReaderWriter.getInstance().recursiveDelete(ZooUtil.getRoot(instance) + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_STATE,
NodeMissingPolicy.SKIP);
- ZooReaderWriter.getRetryingInstance().recursiveDelete(ZooUtil.getRoot(instance) + Constants.ZTABLES + "/" + tableId, NodeMissingPolicy.SKIP);
+ ZooReaderWriter.getInstance().recursiveDelete(ZooUtil.getRoot(instance) + Constants.ZTABLES + "/" + tableId, NodeMissingPolicy.SKIP);
}
}
@@ -312,7 +312,7 @@ public class TableManager {
}
public void removeNamespace(String namespaceId) throws KeeperException, InterruptedException {
- ZooReaderWriter.getRetryingInstance().recursiveDelete(ZooUtil.getRoot(instance) + Constants.ZNAMESPACES + "/" + namespaceId, NodeMissingPolicy.SKIP);
+ ZooReaderWriter.getInstance().recursiveDelete(ZooUtil.getRoot(instance) + Constants.ZNAMESPACES + "/" + namespaceId, NodeMissingPolicy.SKIP);
}
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java b/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java
index 4ae8335..eabdc0d 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java
@@ -48,7 +48,7 @@ public class UniqueNameAllocator {
final int allocate = 100 + rand.nextInt(100);
try {
- byte[] max = ZooReaderWriter.getRetryingInstance().mutate(nextNamePath, null, ZooUtil.PRIVATE, new ZooReaderWriter.Mutator() {
+ byte[] max = ZooReaderWriter.getInstance().mutate(nextNamePath, null, ZooUtil.PRIVATE, new ZooReaderWriter.Mutator() {
public byte[] mutate(byte[] currentValue) throws Exception {
long l = Long.parseLong(new String(currentValue, Constants.UTF8), Character.MAX_RADIX);
l += allocate;
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java
index f7c1e68..b02e5d4 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java
@@ -24,11 +24,11 @@ import org.apache.accumulo.fate.zookeeper.DistributedReadWriteLock;
import org.apache.zookeeper.KeeperException;
public class ZooQueueLock extends org.apache.accumulo.fate.zookeeper.ZooQueueLock {
-
+
public ZooQueueLock(String path, boolean ephemeral) throws KeeperException, InterruptedException {
- super(ZooReaderWriter.getRetryingInstance(), path, ephemeral);
+ super(ZooReaderWriter.getInstance(), path, ephemeral);
}
-
+
public static void main(String args[]) throws InterruptedException, KeeperException {
ZooQueueLock lock = new ZooQueueLock("/lock", true);
DistributedReadWriteLock rlocker = new DistributedReadWriteLock(lock, "reader".getBytes(Constants.UTF8));
@@ -50,5 +50,5 @@ public class ZooQueueLock extends org.apache.accumulo.fate.zookeeper.ZooQueueLoc
readLock.lock();
System.out.println("success");
}
-
+
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
index f950077..435591d 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
@@ -16,25 +16,15 @@
*/
package org.apache.accumulo.server.zookeeper;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
import org.apache.accumulo.core.Constants;
import org.apache.accumulo.core.conf.AccumuloConfiguration;
import org.apache.accumulo.core.conf.Property;
-import org.apache.accumulo.fate.util.UtilWaitThread;
-import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
import org.apache.accumulo.server.conf.ServerConfiguration;
-import org.apache.log4j.Logger;
-import org.apache.zookeeper.KeeperException;
public class ZooReaderWriter extends org.apache.accumulo.fate.zookeeper.ZooReaderWriter {
private static final String SCHEME = "digest";
private static final String USER = "accumulo";
private static ZooReaderWriter instance = null;
- private static IZooReaderWriter retryingInstance = null;
public ZooReaderWriter(String string, int timeInMillis, String secret) {
super(string, timeInMillis, SCHEME, (USER + ":" + secret).getBytes(Constants.UTF8));
@@ -49,39 +39,4 @@ public class ZooReaderWriter extends org.apache.accumulo.fate.zookeeper.ZooReade
return instance;
}
- /**
- * get an instance that retries when zookeeper connection errors occur
- *
- * @return an instance that retries when Zookeeper connection errors occur.
- */
- public static synchronized IZooReaderWriter getRetryingInstance() {
-
- if (retryingInstance == null) {
- final IZooReaderWriter inst = getInstance();
-
- InvocationHandler ih = new InvocationHandler() {
- @Override
- public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
- long retryTime = 250;
- while (true) {
- try {
- return method.invoke(inst, args);
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof KeeperException.ConnectionLossException) {
- Logger.getLogger(ZooReaderWriter.class).warn("Error connecting to zookeeper, will retry in " + retryTime, e.getCause());
- UtilWaitThread.sleep(retryTime);
- retryTime = Math.min(5000, retryTime + 250);
- } else {
- throw e.getCause();
- }
- }
- }
- }
- };
-
- retryingInstance = (IZooReaderWriter) Proxy.newProxyInstance(ZooReaderWriter.class.getClassLoader(), new Class[] {IZooReaderWriter.class}, ih);
- }
-
- return retryingInstance;
- }
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
index 0a9508c..4a7111d 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
@@ -16,14 +16,10 @@
*/
package org.apache.accumulo.server.zookeeper;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Proxy;
-
import org.apache.accumulo.core.Constants;
import org.apache.accumulo.core.conf.AccumuloConfiguration;
import org.apache.accumulo.core.conf.Property;
import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
-import org.apache.accumulo.fate.zookeeper.RetryingInvocationHandler;
import org.apache.accumulo.fate.zookeeper.ZooReaderWriter;
import org.apache.accumulo.server.conf.ServerConfiguration;
@@ -34,7 +30,6 @@ public class ZooReaderWriterFactory {
private static final String SCHEME = "digest";
private static final String USER = "accumulo";
private static IZooReaderWriter instance = null;
- private static IZooReaderWriter retryingInstance = null;
/**
* Gets a new reader/writer.
@@ -66,21 +61,4 @@ public class ZooReaderWriterFactory {
return instance;
}
}
-
- /**
- * Gets a reader/writer, retrieving ZooKeeper information from the site configuration, and that retries on connection loss. The same instance may be returned
- * for multiple calls.
- *
- * @return retrying reader/writer
- */
- public IZooReaderWriter getRetryingInstance() {
- synchronized (ZooReaderWriterFactory.class) {
- if (retryingInstance == null) {
- IZooReaderWriter inst = getInstance();
- InvocationHandler ih = new RetryingInvocationHandler(inst);
- retryingInstance = (IZooReaderWriter) Proxy.newProxyInstance(IZooReaderWriter.class.getClassLoader(), new Class[] {IZooReaderWriter.class}, ih);
- }
- return retryingInstance;
- }
- }
}
[10/16] git commit: ACCUMULO-3242 Rip out the rest of the improper ZK
usages in ZooUtil.
Posted by el...@apache.org.
ACCUMULO-3242 Rip out the rest of the improper ZK usages in ZooUtil.
The way ZooUtil was written made it really hard to correctly handle
session expirations. Remove ZooKeeper as an argument and use ZooSession
(like ZooReader and ZooReaderWriter) which should correctly account
for a new connection.
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/1ce12aea
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/1ce12aea
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/1ce12aea
Branch: refs/heads/1.6
Commit: 1ce12aea2c61ad804e8c27a9a9d1b125bf9d2752
Parents: 6e71636
Author: Josh Elser <el...@apache.org>
Authored: Sat Oct 18 15:46:56 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:16:04 2014 -0400
----------------------------------------------------------------------
.../fate/zookeeper/IZooReaderWriter.java | 35 ++---
.../apache/accumulo/fate/zookeeper/Retry.java | 4 +-
.../accumulo/fate/zookeeper/RetryFactory.java | 6 +-
.../accumulo/fate/zookeeper/ZooReader.java | 2 +-
.../fate/zookeeper/ZooReaderWriter.java | 29 ++--
.../apache/accumulo/fate/zookeeper/ZooUtil.java | 143 +++++++++++--------
.../apache/accumulo/server/init/Initialize.java | 10 +-
7 files changed, 137 insertions(+), 92 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
index afc2250..2f3ed62 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
@@ -25,44 +25,47 @@ import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
public interface IZooReaderWriter extends IZooReader {
-
+
ZooKeeper getZooKeeper();
-
+
void recursiveDelete(String zPath, NodeMissingPolicy policy) throws KeeperException, InterruptedException;
-
+
void recursiveDelete(String zPath, int version, NodeMissingPolicy policy) throws KeeperException, InterruptedException;
-
+
/**
* Create a persistent node with the default ACL
- *
+ *
* @return true if the node was created or altered; false if it was skipped
*/
boolean putPersistentData(String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException;
-
+
boolean putPrivatePersistentData(String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException;
-
+
void putPersistentData(String zPath, byte[] data, int version, NodeExistsPolicy policy) throws KeeperException, InterruptedException;
+ boolean putPersistentData(String zPath, byte[] data, int version, NodeExistsPolicy policy, List<ACL> acls) throws KeeperException, InterruptedException;
+
String putPersistentSequential(String zPath, byte[] data) throws KeeperException, InterruptedException;
-
+
String putEphemeralSequential(String zPath, byte[] data) throws KeeperException, InterruptedException;
-
+
String putEphemeralData(String zPath, byte[] data) throws KeeperException, InterruptedException;
void recursiveCopyPersistent(String source, String destination, NodeExistsPolicy policy) throws KeeperException, InterruptedException;
-
+
void delete(String path, int version) throws InterruptedException, KeeperException;
-
+
interface Mutator {
byte[] mutate(byte[] currentValue) throws Exception;
}
-
+
byte[] mutate(String zPath, byte[] createValue, List<ACL> acl, Mutator mutator) throws Exception;
-
+
boolean isLockHeld(ZooUtil.LockID lockID) throws KeeperException, InterruptedException;
-
+
void mkdirs(String path) throws KeeperException, InterruptedException;
-
+
+ @Override
void sync(String path) throws KeeperException, InterruptedException;
-
+
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
index 4a37172..63aa902 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
@@ -19,7 +19,7 @@ package org.apache.accumulo.fate.zookeeper;
import org.apache.log4j.Logger;
/**
- *
+ * Encapsulates the retrying implementation for some operation. Provides bounded retry attempts with a bounded, linear backoff.
*/
public class Retry {
private static final Logger log = Logger.getLogger(Retry.class);
@@ -37,7 +37,7 @@ public class Retry {
* @param waitIncrement
* The amount of time (ms) to increment next wait time by
*/
- public Retry(long maxRetries, long startWait, long maxWait, long waitIncrement) {
+ public Retry(long maxRetries, long startWait, long waitIncrement, long maxWait) {
this.maxRetries = maxRetries;
this.maxWait = maxWait;
this.waitIncrement = waitIncrement;
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
index 3fcb738..ff96350 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
@@ -17,13 +17,15 @@
package org.apache.accumulo.fate.zookeeper;
/**
- *
+ * Creates {@link Retry} instances with the given parameters
*/
public class RetryFactory {
+ public static final long DEFAULT_MAX_RETRIES = 10l, DEFAULT_START_WAIT = 250l, DEFAULT_WAIT_INCREMENT = 250l, DEFAULT_MAX_WAIT = 5000l;
+ public static final RetryFactory DEFAULT_INSTANCE = new RetryFactory(DEFAULT_MAX_RETRIES, DEFAULT_START_WAIT, DEFAULT_WAIT_INCREMENT, DEFAULT_MAX_WAIT);
private final long maxRetries, startWait, maxWait, waitIncrement;
- public RetryFactory(long maxRetries, long startWait, long maxWait, long waitIncrement) {
+ public RetryFactory(long maxRetries, long startWait, long waitIncrement, long maxWait) {
this.maxRetries = maxRetries;
this.startWait = startWait;
this.maxWait = maxWait;
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
index fd7938a..5706cf3 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
@@ -223,6 +223,6 @@ public class ZooReader implements IZooReader {
public ZooReader(String keepers, int timeout) {
this.keepers = keepers;
this.timeout = timeout;
- this.retryFactory = new RetryFactory(10l, 250l, 250l, 5000l);
+ this.retryFactory = RetryFactory.DEFAULT_INSTANCE;
}
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
index 79c2219..5b6447c 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
@@ -22,6 +22,7 @@ import java.util.List;
import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeMissingPolicy;
+import org.apache.accumulo.fate.zookeeper.ZooUtil.ZooKeeperConnectionInfo;
import org.apache.log4j.Logger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
@@ -38,6 +39,7 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
private static ZooReaderWriter instance = null;
private final String scheme;
private final byte[] auth;
+ private final ZooKeeperConnectionInfo info;
@Override
public ZooKeeper getZooKeeper() {
@@ -52,16 +54,17 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
super(string, timeInMillis);
this.scheme = scheme;
this.auth = Arrays.copyOf(auth, auth.length);
+ this.info = new ZooKeeperConnectionInfo(string, timeInMillis, scheme, this.auth);
}
@Override
public void recursiveDelete(String zPath, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
- ZooUtil.recursiveDelete(getZooKeeper(), zPath, policy);
+ ZooUtil.recursiveDelete(info, zPath, policy);
}
@Override
public void recursiveDelete(String zPath, int version, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
- ZooUtil.recursiveDelete(getZooKeeper(), zPath, version, policy);
+ ZooUtil.recursiveDelete(info, zPath, version, policy);
}
/**
@@ -71,37 +74,43 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
*/
@Override
public boolean putPersistentData(String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
- return ZooUtil.putPersistentData(getZooKeeper(), zPath, data, policy);
+ return ZooUtil.putPersistentData(info, zPath, data, policy);
+ }
+
+ @Override
+ public boolean putPersistentData(String zPath, byte[] data, int version, NodeExistsPolicy policy, List<ACL> acls) throws KeeperException,
+ InterruptedException {
+ return ZooUtil.putPersistentData(info, zPath, data, version, policy, acls);
}
@Override
public boolean putPrivatePersistentData(String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
- return ZooUtil.putPrivatePersistentData(getZooKeeper(), zPath, data, policy);
+ return ZooUtil.putPrivatePersistentData(info, zPath, data, policy);
}
@Override
public void putPersistentData(String zPath, byte[] data, int version, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
- ZooUtil.putPersistentData(getZooKeeper(), zPath, data, version, policy);
+ ZooUtil.putPersistentData(info, zPath, data, version, policy);
}
@Override
public String putPersistentSequential(String zPath, byte[] data) throws KeeperException, InterruptedException {
- return ZooUtil.putPersistentSequential(getZooKeeper(), zPath, data);
+ return ZooUtil.putPersistentSequential(info, zPath, data);
}
@Override
public String putEphemeralData(String zPath, byte[] data) throws KeeperException, InterruptedException {
- return ZooUtil.putEphemeralData(getZooKeeper(), zPath, data);
+ return ZooUtil.putEphemeralData(info, zPath, data);
}
@Override
public String putEphemeralSequential(String zPath, byte[] data) throws KeeperException, InterruptedException {
- return ZooUtil.putEphemeralSequential(getZooKeeper(), zPath, data);
+ return ZooUtil.putEphemeralSequential(info, zPath, data);
}
@Override
public void recursiveCopyPersistent(String source, String destination, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
- ZooUtil.recursiveCopyPersistent(getZooKeeper(), source, destination, policy);
+ ZooUtil.recursiveCopyPersistent(info, source, destination, policy);
}
@Override
@@ -189,7 +198,7 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
@Override
public boolean isLockHeld(ZooUtil.LockID lockID) throws KeeperException, InterruptedException {
- return ZooUtil.isLockHeld(getZooKeeper(), lockID);
+ return ZooUtil.isLockHeld(info, lockID);
}
@Override
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
index e0d8831..674c1d8 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
@@ -81,6 +81,19 @@ public class ZooUtil {
}
}
+ protected static class ZooKeeperConnectionInfo {
+ String keepers, scheme;
+ int timeout;
+ byte[] auth;
+
+ public ZooKeeperConnectionInfo(String keepers, int timeout, String scheme, byte[] auth) {
+ this.keepers = keepers;
+ this.timeout = timeout;
+ this.scheme = scheme;
+ this.auth = auth;
+ }
+ }
+
public static final List<ACL> PRIVATE;
public static final List<ACL> PUBLIC;
private static final RetryFactory RETRY_FACTORY;
@@ -90,7 +103,15 @@ public class ZooUtil {
PUBLIC = new ArrayList<ACL>();
PUBLIC.addAll(PRIVATE);
PUBLIC.add(new ACL(Perms.READ, Ids.ANYONE_ID_UNSAFE));
- RETRY_FACTORY = new RetryFactory(10l, 250l, 250l, 5000l);
+ RETRY_FACTORY = RetryFactory.DEFAULT_INSTANCE;
+ }
+
+ protected static ZooKeeper getZooKeeper(ZooKeeperConnectionInfo info) {
+ return getZooKeeper(info.keepers, info.timeout, info.scheme, info.auth);
+ }
+
+ protected static ZooKeeper getZooKeeper(String keepers, int timeout, String scheme, byte[] auth) {
+ return ZooSession.getSession(keepers, timeout, scheme, auth);
}
protected static void retryOrThrow(Retry retry, KeeperException e) throws KeeperException {
@@ -110,7 +131,7 @@ public class ZooUtil {
* @param zPath
* the path to delete
*/
- public static void recursiveDelete(ZooKeeper zk, String zPath, int version, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
+ static void recursiveDelete(ZooKeeperConnectionInfo info, String zPath, int version, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
if (policy.equals(NodeMissingPolicy.CREATE))
throw new IllegalArgumentException(policy.name() + " is invalid for this operation");
try {
@@ -118,12 +139,11 @@ public class ZooUtil {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- children = zk.getChildren(zPath, false);
+ children = getZooKeeper(info).getChildren(zPath, false);
break;
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -132,17 +152,17 @@ public class ZooUtil {
retry.waitForNextAttempt();
}
for (String child : children)
- recursiveDelete(zk, zPath + "/" + child, NodeMissingPolicy.SKIP);
+ recursiveDelete(info, zPath + "/" + child, NodeMissingPolicy.SKIP);
Stat stat;
while (true) {
try {
- stat = zk.exists(zPath, null);
+ stat = getZooKeeper(info).exists(zPath, null);
// Node exists
if (stat != null) {
try {
// Try to delete it
- zk.delete(zPath, stat.getVersion());
+ getZooKeeper(info).delete(zPath, stat.getVersion());
return;
} catch (NoNodeException e) {
// If the node is gone now, it's ok if we have SKIP
@@ -156,7 +176,6 @@ public class ZooUtil {
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -172,8 +191,8 @@ public class ZooUtil {
}
}
- public static void recursiveDelete(ZooKeeper zk, String zPath, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
- recursiveDelete(zk, zPath, -1, policy);
+ public static void recursiveDelete(ZooKeeperConnectionInfo info, String zPath, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
+ recursiveDelete(info, zPath, -1, policy);
}
/**
@@ -181,21 +200,24 @@ public class ZooUtil {
*
* @return true if the node was created or altered; false if it was skipped
*/
- public static boolean putPersistentData(ZooKeeper zk, String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
- return putData(zk, zPath, data, CreateMode.PERSISTENT, -1, policy, PUBLIC);
+ public static boolean putPersistentData(ZooKeeperConnectionInfo info, String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException,
+ InterruptedException {
+ return putData(info, zPath, data, CreateMode.PERSISTENT, -1, policy, PUBLIC);
}
- public static boolean putPersistentData(ZooKeeper zk, String zPath, byte[] data, int version, NodeExistsPolicy policy) throws KeeperException,
+ public static boolean putPersistentData(ZooKeeperConnectionInfo info, String zPath, byte[] data, int version, NodeExistsPolicy policy)
+ throws KeeperException,
InterruptedException {
- return putData(zk, zPath, data, CreateMode.PERSISTENT, version, policy, PUBLIC);
+ return putData(info, zPath, data, CreateMode.PERSISTENT, version, policy, PUBLIC);
}
- public static boolean putPersistentData(ZooKeeper zk, String zPath, byte[] data, int version, NodeExistsPolicy policy, List<ACL> acls)
+ public static boolean putPersistentData(ZooKeeperConnectionInfo info, String zPath, byte[] data, int version, NodeExistsPolicy policy, List<ACL> acls)
throws KeeperException, InterruptedException {
- return putData(zk, zPath, data, CreateMode.PERSISTENT, version, policy, acls);
+ return putData(info, zPath, data, CreateMode.PERSISTENT, version, policy, acls);
}
- private static boolean putData(ZooKeeper zk, String zPath, byte[] data, CreateMode mode, int version, NodeExistsPolicy policy, List<ACL> acls)
+ private static boolean putData(ZooKeeperConnectionInfo info, String zPath, byte[] data, CreateMode mode, int version,
+ NodeExistsPolicy policy, List<ACL> acls)
throws KeeperException, InterruptedException {
if (policy == null)
policy = NodeExistsPolicy.FAIL;
@@ -203,7 +225,7 @@ public class ZooUtil {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- zk.create(zPath, data, acls, mode);
+ getZooKeeper(info).create(zPath, data, acls, mode);
return true;
} catch (KeeperException e) {
final Code code = e.code();
@@ -214,26 +236,24 @@ public class ZooUtil {
case OVERWRITE:
// overwrite the data in the node when it already exists
try {
- zk.setData(zPath, data, version);
+ getZooKeeper(info).setData(zPath, data, version);
return true;
} catch (KeeperException e2) {
final Code code2 = e2.code();
if (code2 == Code.NONODE) {
// node delete between create call and set data, so try create call again
continue;
- } else if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
- retryOrThrow(retry, e);
+ } else if (code2 == Code.CONNECTIONLOSS || code2 == Code.OPERATIONTIMEOUT || code2 == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e2);
} else {
// unhandled exception on setData()
- throw e;
+ throw e2;
}
}
default:
throw e;
}
} else if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
// unhandled exception on create()
@@ -246,15 +266,14 @@ public class ZooUtil {
}
}
- public static byte[] getData(ZooKeeper zk, String zPath, Stat stat) throws KeeperException, InterruptedException {
+ public static byte[] getData(ZooKeeperConnectionInfo info, String zPath, Stat stat) throws KeeperException, InterruptedException {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- return zk.getData(zPath, false, stat);
+ return getZooKeeper(info).getData(zPath, false, stat);
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -265,15 +284,14 @@ public class ZooUtil {
}
}
- public static Stat getStatus(ZooKeeper zk, String zPath) throws KeeperException, InterruptedException {
+ public static Stat getStatus(ZooKeeperConnectionInfo info, String zPath) throws KeeperException, InterruptedException {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- return zk.exists(zPath, false);
+ return getZooKeeper(info).exists(zPath, false);
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -284,16 +302,16 @@ public class ZooUtil {
}
}
- public static boolean exists(ZooKeeper zk, String zPath) throws KeeperException, InterruptedException {
- return getStatus(zk, zPath) != null;
+ public static boolean exists(ZooKeeperConnectionInfo info, String zPath) throws KeeperException, InterruptedException {
+ return getStatus(info, zPath) != null;
}
- public static void recursiveCopyPersistent(ZooKeeper zk, String source, String destination, NodeExistsPolicy policy) throws KeeperException,
+ public static void recursiveCopyPersistent(ZooKeeperConnectionInfo info, String source, String destination, NodeExistsPolicy policy) throws KeeperException,
InterruptedException {
Stat stat = null;
- if (!exists(zk, source))
+ if (!exists(info, source))
throw KeeperException.create(Code.NONODE, source);
- if (exists(zk, destination)) {
+ if (exists(info, destination)) {
switch (policy) {
case OVERWRITE:
break;
@@ -306,31 +324,48 @@ public class ZooUtil {
}
stat = new Stat();
- byte[] data = getData(zk, source, stat);
+ byte[] data = getData(info, source, stat);
if (stat.getEphemeralOwner() == 0) {
if (data == null)
throw KeeperException.create(Code.NONODE, source);
- putPersistentData(zk, destination, data, policy);
- if (stat.getNumChildren() > 0)
- for (String child : zk.getChildren(source, false))
- recursiveCopyPersistent(zk, source + "/" + child, destination + "/" + child, policy);
+ putPersistentData(info, destination, data, policy);
+ if (stat.getNumChildren() > 0) {
+ List<String> children;
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ children = getZooKeeper(info).getChildren(source, false);
+ break;
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+ retry.waitForNextAttempt();
+ }
+ for (String child : children)
+ recursiveCopyPersistent(info, source + "/" + child, destination + "/" + child, policy);
+ }
}
}
- public static boolean putPrivatePersistentData(ZooKeeper zk, String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
- return putData(zk, zPath, data, CreateMode.PERSISTENT, -1, policy, PRIVATE);
+ public static boolean putPrivatePersistentData(ZooKeeperConnectionInfo info, String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException,
+ InterruptedException {
+ return putData(info, zPath, data, CreateMode.PERSISTENT, -1, policy, PRIVATE);
}
- public static String putPersistentSequential(ZooKeeper zk, String zPath, byte[] data) throws KeeperException, InterruptedException {
+ public static String putPersistentSequential(ZooKeeperConnectionInfo info, String zPath, byte[] data) throws KeeperException, InterruptedException {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.PERSISTENT_SEQUENTIAL);
+ return getZooKeeper(info).create(zPath, data, ZooUtil.PUBLIC, CreateMode.PERSISTENT_SEQUENTIAL);
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -341,15 +376,14 @@ public class ZooUtil {
}
}
- public static String putEphemeralData(ZooKeeper zk, String zPath, byte[] data) throws KeeperException, InterruptedException {
+ public static String putEphemeralData(ZooKeeperConnectionInfo info, String zPath, byte[] data) throws KeeperException, InterruptedException {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL);
+ return getZooKeeper(info).create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL);
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -360,15 +394,14 @@ public class ZooUtil {
}
}
- public static String putEphemeralSequential(ZooKeeper zk, String zPath, byte[] data) throws KeeperException, InterruptedException {
+ public static String putEphemeralSequential(ZooKeeperConnectionInfo info, String zPath, byte[] data) throws KeeperException, InterruptedException {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL_SEQUENTIAL);
+ return getZooKeeper(info).create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL_SEQUENTIAL);
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -395,12 +428,11 @@ public class ZooUtil {
return zc.get(path + "/" + lockNode);
}
- public static boolean isLockHeld(ZooKeeper zk, LockID lid) throws KeeperException, InterruptedException {
+ public static boolean isLockHeld(ZooKeeperConnectionInfo info, LockID lid) throws KeeperException, InterruptedException {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- // TODO push down retry to getChildren and exists
- List<String> children = zk.getChildren(lid.path, false);
+ List<String> children = getZooKeeper(info).getChildren(lid.path, false);
if (children.size() == 0) {
return false;
@@ -412,12 +444,11 @@ public class ZooUtil {
if (!lid.node.equals(lockNode))
return false;
- Stat stat = zk.exists(lid.path + "/" + lid.node, false);
+ Stat stat = getZooKeeper(info).exists(lid.path + "/" + lid.node, false);
return stat != null && stat.getEphemeralOwner() == lid.eid;
} catch (KeeperException ex) {
final Code c = ex.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, ex);
}
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java b/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
index 5cbffc3..fcecc37 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
@@ -83,7 +83,7 @@ import com.beust.jcommander.Parameter;
/**
* This class is used to setup the directory structure and the root tablet to get an instance started
- *
+ *
*/
public class Initialize {
private static final Logger log = Logger.getLogger(Initialize.class);
@@ -101,7 +101,7 @@ public class Initialize {
/**
* Sets this class's ZooKeeper reader/writer.
- *
+ *
* @param izoo
* reader/writer
*/
@@ -111,7 +111,7 @@ public class Initialize {
/**
* Gets this class's ZooKeeper reader/writer.
- *
+ *
* @return reader/writer
*/
static IZooReaderWriter getZooReaderWriter() {
@@ -421,8 +421,8 @@ public class Initialize {
private static void initZooKeeper(Opts opts, String uuid, String instanceNamePath, Path rootTablet) throws KeeperException, InterruptedException {
// setup basic data in zookeeper
- ZooUtil.putPersistentData(zoo.getZooKeeper(), Constants.ZROOT, new byte[0], -1, NodeExistsPolicy.SKIP, Ids.OPEN_ACL_UNSAFE);
- ZooUtil.putPersistentData(zoo.getZooKeeper(), Constants.ZROOT + Constants.ZINSTANCES, new byte[0], -1, NodeExistsPolicy.SKIP, Ids.OPEN_ACL_UNSAFE);
+ zoo.putPersistentData(Constants.ZROOT, new byte[0], -1, NodeExistsPolicy.SKIP, Ids.OPEN_ACL_UNSAFE);
+ zoo.putPersistentData(Constants.ZROOT + Constants.ZINSTANCES, new byte[0], -1, NodeExistsPolicy.SKIP, Ids.OPEN_ACL_UNSAFE);
// setup instance name
if (opts.clearInstanceName)
[15/16] Merge branch '1.6'
Posted by el...@apache.org.
http://git-wip-us.apache.org/repos/asf/accumulo/blob/8bea7aba/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
----------------------------------------------------------------------
diff --cc server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
index cabf689,0000000..caff246
mode 100644,000000..100644
--- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
+++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/Tablet.java
@@@ -1,2675 -1,0 +1,2675 @@@
+/*
+ * 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.accumulo.tserver.tablet;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.PriorityQueue;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.client.Durability;
+import org.apache.accumulo.core.client.IteratorSetting;
+import org.apache.accumulo.core.client.impl.DurabilityImpl;
+import org.apache.accumulo.core.client.impl.ScannerImpl;
+import org.apache.accumulo.core.client.impl.Tables;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.ConfigurationCopy;
+import org.apache.accumulo.core.conf.ConfigurationObserver;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.constraints.Violations;
+import org.apache.accumulo.core.data.ByteSequence;
+import org.apache.accumulo.core.data.Column;
+import org.apache.accumulo.core.data.ColumnUpdate;
+import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.KeyExtent;
+import org.apache.accumulo.core.data.Mutation;
+import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.data.thrift.IterInfo;
+import org.apache.accumulo.core.data.thrift.MapFileInfo;
+import org.apache.accumulo.core.file.FileOperations;
+import org.apache.accumulo.core.file.FileSKVIterator;
+import org.apache.accumulo.core.iterators.IterationInterruptedException;
+import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope;
+import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
+import org.apache.accumulo.core.iterators.system.SourceSwitchingIterator;
+import org.apache.accumulo.core.master.thrift.TabletLoadState;
+import org.apache.accumulo.core.metadata.MetadataTable;
+import org.apache.accumulo.core.metadata.RootTable;
+import org.apache.accumulo.core.metadata.schema.DataFileValue;
+import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection;
+import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.DataFileColumnFamily;
+import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.LogColumnFamily;
+import org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.ScanFileColumnFamily;
+import org.apache.accumulo.core.protobuf.ProtobufUtil;
+import org.apache.accumulo.core.replication.ReplicationConfigurationUtil;
+import org.apache.accumulo.core.replication.StatusUtil;
+import org.apache.accumulo.core.replication.proto.Replication.Status;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.security.ColumnVisibility;
+import org.apache.accumulo.core.security.Credentials;
+import org.apache.accumulo.core.tabletserver.log.LogEntry;
+import org.apache.accumulo.core.tabletserver.thrift.TabletStats;
+import org.apache.accumulo.core.util.LocalityGroupUtil;
+import org.apache.accumulo.core.util.Pair;
+import org.apache.accumulo.core.util.UtilWaitThread;
+import org.apache.accumulo.server.client.HdfsZooInstance;
+import org.apache.accumulo.server.conf.TableConfiguration;
+import org.apache.accumulo.server.fs.FileRef;
+import org.apache.accumulo.server.fs.VolumeManager;
+import org.apache.accumulo.server.fs.VolumeManager.FileType;
+import org.apache.accumulo.server.fs.VolumeUtil;
+import org.apache.accumulo.server.fs.VolumeUtil.TabletFiles;
+import org.apache.accumulo.server.master.state.TServerInstance;
+import org.apache.accumulo.server.master.tableOps.CompactionIterators;
+import org.apache.accumulo.server.problems.ProblemReport;
+import org.apache.accumulo.server.problems.ProblemReports;
+import org.apache.accumulo.server.problems.ProblemType;
+import org.apache.accumulo.server.security.SystemCredentials;
+import org.apache.accumulo.server.tablets.TabletTime;
+import org.apache.accumulo.server.tablets.UniqueNameAllocator;
+import org.apache.accumulo.server.util.FileUtil;
+import org.apache.accumulo.server.util.MasterMetadataUtil;
+import org.apache.accumulo.server.util.MetadataTableUtil;
+import org.apache.accumulo.server.util.ReplicationTableUtil;
+import org.apache.accumulo.server.util.TabletOperations;
+import org.apache.accumulo.server.zookeeper.ZooReaderWriter;
+import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader;
+import org.apache.accumulo.trace.instrument.Span;
+import org.apache.accumulo.trace.instrument.Trace;
+import org.apache.accumulo.tserver.InMemoryMap;
+import org.apache.accumulo.tserver.MinorCompactionReason;
+import org.apache.accumulo.tserver.TConstraintViolationException;
+import org.apache.accumulo.tserver.TLevel;
+import org.apache.accumulo.tserver.TabletServer;
+import org.apache.accumulo.tserver.TabletServerResourceManager.TabletResourceManager;
+import org.apache.accumulo.tserver.TabletStatsKeeper;
+import org.apache.accumulo.tserver.TabletStatsKeeper.Operation;
+import org.apache.accumulo.tserver.TooManyFilesException;
+import org.apache.accumulo.tserver.TservConstraintEnv;
+import org.apache.accumulo.tserver.compaction.CompactionPlan;
+import org.apache.accumulo.tserver.compaction.CompactionStrategy;
+import org.apache.accumulo.tserver.compaction.DefaultCompactionStrategy;
+import org.apache.accumulo.tserver.compaction.MajorCompactionReason;
+import org.apache.accumulo.tserver.compaction.MajorCompactionRequest;
+import org.apache.accumulo.tserver.compaction.WriteParameters;
+import org.apache.accumulo.tserver.constraints.ConstraintChecker;
+import org.apache.accumulo.tserver.log.DfsLogger;
+import org.apache.accumulo.tserver.log.MutationReceiver;
+import org.apache.accumulo.tserver.mastermessage.TabletStatusMessage;
+import org.apache.accumulo.tserver.metrics.TabletServerMinCMetrics;
+import org.apache.accumulo.tserver.tablet.Compactor.CompactionCanceledException;
+import org.apache.accumulo.tserver.tablet.Compactor.CompactionEnv;
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.io.Text;
+import org.apache.log4j.Logger;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.KeeperException.NoNodeException;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ *
+ * Provide access to a single row range in a living TabletServer.
+ *
+ */
+public class Tablet implements TabletCommitter {
+ static private final Logger log = Logger.getLogger(Tablet.class);
+ static private final List<LogEntry> NO_LOG_ENTRIES = Collections.emptyList();
+
+ private final TabletServer tabletServer;
+ private final KeyExtent extent;
+ private final TabletResourceManager tabletResources;
+ private final DatafileManager datafileManager;
+ private final TableConfiguration tableConfiguration;
+ private final String tabletDirectory;
+ private final Path location; // absolute path of this tablets dir
+
+ private final TabletMemory tabletMemory;
+
+ private final TabletTime tabletTime;
+ private final Object timeLock = new Object();
+ private long persistedTime;
+
+ private TServerInstance lastLocation;
+ private volatile boolean tableDirChecked = false;
+
+ private final AtomicLong dataSourceDeletions = new AtomicLong(0);
+
+ public long getDataSourceDeletions() {
+ return dataSourceDeletions.get();
+ }
+
+ private final Set<ScanDataSource> activeScans = new HashSet<ScanDataSource>();
+
+ private static enum CloseState {
+ OPEN, CLOSING, CLOSED, COMPLETE
+ }
+
+ private volatile CloseState closeState = CloseState.OPEN;
+
+ private boolean updatingFlushID = false;
+
+ private long lastFlushID = -1;
+ private long lastCompactID = -1;
+
+ private static class CompactionWaitInfo {
+ long flushID = -1;
+ long compactionID = -1;
+ }
+
+ // stores info about user initiated major compaction that is waiting on a minor compaction to finish
+ private CompactionWaitInfo compactionWaitInfo = new CompactionWaitInfo();
+
+ static enum CompactionState {
+ WAITING_TO_START, IN_PROGRESS
+ };
+
+ private volatile CompactionState minorCompactionState = null;
+ private volatile CompactionState majorCompactionState = null;
+
+ private final Set<MajorCompactionReason> majorCompactionQueued = Collections.synchronizedSet(EnumSet.noneOf(MajorCompactionReason.class));
+
+ private final AtomicReference<ConstraintChecker> constraintChecker = new AtomicReference<ConstraintChecker>();
+
+ private int writesInProgress = 0;
+
+ private final TabletStatsKeeper timer = new TabletStatsKeeper();
+
+ private final Rate queryRate = new Rate(0.2);
+ private long queryCount = 0;
+
+ private final Rate queryByteRate = new Rate(0.2);
+ private long queryBytes = 0;
+
+ private final Rate ingestRate = new Rate(0.2);
+ private long ingestCount = 0;
+
+ private final Rate ingestByteRate = new Rate(0.2);
+ private long ingestBytes = 0;
+
+ private byte[] defaultSecurityLabel = new byte[0];
+
+ private long lastMinorCompactionFinishTime = 0;
+ private long lastMapFileImportTime = 0;
+
+ private volatile long numEntries = 0;
+ private volatile long numEntriesInMemory = 0;
+
+ private final Rate scannedRate = new Rate(0.2);
+ private final AtomicLong scannedCount = new AtomicLong(0);
+
+ private final ConfigurationObserver configObserver;
+
+ private final int logId;
+
+ @Override
+ public int getLogId() {
+ return logId;
+ }
+
+ public static class LookupResult {
+ public List<Range> unfinishedRanges = new ArrayList<Range>();
+ public long bytesAdded = 0;
+ public long dataSize = 0;
+ public boolean closed = false;
+ }
+
+ FileRef getNextMapFilename(String prefix) throws IOException {
+ String extension = FileOperations.getNewFileExtension(tableConfiguration);
+ checkTabletDir();
+ return new FileRef(location.toString() + "/" + prefix + UniqueNameAllocator.getInstance().getNextName() + "." + extension);
+ }
+
+ private void checkTabletDir() throws IOException {
+ if (!tableDirChecked) {
+ FileStatus[] files = null;
+ try {
+ files = getTabletServer().getFileSystem().listStatus(location);
+ } catch (FileNotFoundException ex) {
+ // ignored
+ }
+
+ if (files == null) {
+ if (location.getName().startsWith(Constants.CLONE_PREFIX))
+ log.debug("Tablet " + extent + " had no dir, creating " + location); // its a clone dir...
+ else
+ log.warn("Tablet " + extent + " had no dir, creating " + location);
+
+ getTabletServer().getFileSystem().mkdirs(location);
+ }
+ tableDirChecked = true;
+ }
+ }
+
+ /**
+ * Only visible for testing
+ */
+ @VisibleForTesting
+ protected Tablet(TabletTime tabletTime, String tabletDirectory, int logId, Path location, DatafileManager datafileManager, TabletServer tabletServer,
+ TabletResourceManager tabletResources, TabletMemory tabletMemory, TableConfiguration tableConfiguration, KeyExtent extent,
+ ConfigurationObserver configObserver) {
+ this.tabletTime = tabletTime;
+ this.tabletDirectory = tabletDirectory;
+ this.logId = logId;
+ this.location = location;
+ this.datafileManager = datafileManager;
+ this.tabletServer = tabletServer;
+ this.tabletResources = tabletResources;
+ this.tabletMemory = tabletMemory;
+ this.tableConfiguration = tableConfiguration;
+ this.extent = extent;
+ this.configObserver = configObserver;
+ }
+
+ public Tablet(TabletServer tabletServer, KeyExtent extent, TabletResourceManager trm, SplitInfo info) throws IOException {
+ this(tabletServer, new Text(info.getDir()), extent, trm, info.getDatafiles(), info.getTime(), info.getInitFlushID(), info.getInitCompactID(), info
+ .getLastLocation());
+ splitCreationTime = System.currentTimeMillis();
+ }
+
+ private Tablet(TabletServer tabletServer, Text location, KeyExtent extent, TabletResourceManager trm, SortedMap<FileRef,DataFileValue> datafiles,
+ String time, long initFlushID, long initCompactID, TServerInstance lastLocation) throws IOException {
+ this(tabletServer, extent, location, trm, NO_LOG_ENTRIES, datafiles, time, lastLocation, new HashSet<FileRef>(), initFlushID, initCompactID);
+ }
+
+ private static String lookupTime(AccumuloConfiguration conf, KeyExtent extent, SortedMap<Key,Value> tabletsKeyValues) {
+ SortedMap<Key,Value> entries;
+
+ if (extent.isRootTablet()) {
+ return null;
+ } else {
+ entries = new TreeMap<Key,Value>();
+ Text rowName = extent.getMetadataEntry();
+ for (Entry<Key,Value> entry : tabletsKeyValues.entrySet()) {
+ if (entry.getKey().compareRow(rowName) == 0 && TabletsSection.ServerColumnFamily.TIME_COLUMN.hasColumns(entry.getKey())) {
+ entries.put(new Key(entry.getKey()), new Value(entry.getValue()));
+ }
+ }
+ }
+
+ if (entries.size() == 1)
+ return entries.values().iterator().next().toString();
+ return null;
+ }
+
+ private static SortedMap<FileRef,DataFileValue> lookupDatafiles(AccumuloConfiguration conf, VolumeManager fs, KeyExtent extent,
+ SortedMap<Key,Value> tabletsKeyValues) throws IOException {
+
+ TreeMap<FileRef,DataFileValue> datafiles = new TreeMap<FileRef,DataFileValue>();
+
+ if (extent.isRootTablet()) { // the meta0 tablet
+ Path location = new Path(MetadataTableUtil.getRootTabletDir());
+
+ // cleanUpFiles() has special handling for delete. files
+ FileStatus[] files = fs.listStatus(location);
+ Collection<String> goodPaths = RootFiles.cleanupReplacement(fs, files, true);
+ for (String good : goodPaths) {
+ Path path = new Path(good);
+ String filename = path.getName();
+ FileRef ref = new FileRef(location.toString() + "/" + filename, path);
+ DataFileValue dfv = new DataFileValue(0, 0);
+ datafiles.put(ref, dfv);
+ }
+ } else {
+
+ Text rowName = extent.getMetadataEntry();
+
+ String tableId = extent.isMeta() ? RootTable.ID : MetadataTable.ID;
+ ScannerImpl mdScanner = new ScannerImpl(HdfsZooInstance.getInstance(), SystemCredentials.get(), tableId, Authorizations.EMPTY);
+
+ // Commented out because when no data file is present, each tablet will scan through metadata table and return nothing
+ // reduced batch size to improve performance
+ // changed here after endKeys were implemented from 10 to 1000
+ mdScanner.setBatchSize(1000);
+
+ // leave these in, again, now using endKey for safety
+ mdScanner.fetchColumnFamily(DataFileColumnFamily.NAME);
+
+ mdScanner.setRange(new Range(rowName));
+
+ for (Entry<Key,Value> entry : mdScanner) {
+ if (entry.getKey().compareRow(rowName) != 0) {
+ break;
+ }
+
+ FileRef ref = new FileRef(fs, entry.getKey());
+ datafiles.put(ref, new DataFileValue(entry.getValue().get()));
+ }
+ }
+ return datafiles;
+ }
+
+ private static List<LogEntry> lookupLogEntries(KeyExtent ke, SortedMap<Key,Value> tabletsKeyValues) {
+ List<LogEntry> logEntries = new ArrayList<LogEntry>();
+
+ if (ke.isMeta()) {
+ try {
+ logEntries = MetadataTableUtil.getLogEntries(SystemCredentials.get(), ke);
+ } catch (Exception ex) {
+ throw new RuntimeException("Unable to read tablet log entries", ex);
+ }
+ } else {
+ log.debug("Looking at metadata " + tabletsKeyValues);
+ Text row = ke.getMetadataEntry();
+ for (Entry<Key,Value> entry : tabletsKeyValues.entrySet()) {
+ Key key = entry.getKey();
+ if (key.getRow().equals(row)) {
+ if (key.getColumnFamily().equals(LogColumnFamily.NAME)) {
+ logEntries.add(LogEntry.fromKeyValue(key, entry.getValue()));
+ }
+ }
+ }
+ }
+
+ log.debug("got " + logEntries + " for logs for " + ke);
+ return logEntries;
+ }
+
+ private static Set<FileRef> lookupScanFiles(KeyExtent extent, SortedMap<Key,Value> tabletsKeyValues, VolumeManager fs) throws IOException {
+ HashSet<FileRef> scanFiles = new HashSet<FileRef>();
+
+ Text row = extent.getMetadataEntry();
+ for (Entry<Key,Value> entry : tabletsKeyValues.entrySet()) {
+ Key key = entry.getKey();
+ if (key.getRow().equals(row) && key.getColumnFamily().equals(ScanFileColumnFamily.NAME)) {
+ scanFiles.add(new FileRef(fs, key));
+ }
+ }
+
+ return scanFiles;
+ }
+
+ private static long lookupFlushID(KeyExtent extent, SortedMap<Key,Value> tabletsKeyValues) {
+ Text row = extent.getMetadataEntry();
+ for (Entry<Key,Value> entry : tabletsKeyValues.entrySet()) {
+ Key key = entry.getKey();
+ if (key.getRow().equals(row) && TabletsSection.ServerColumnFamily.FLUSH_COLUMN.equals(key.getColumnFamily(), key.getColumnQualifier()))
+ return Long.parseLong(entry.getValue().toString());
+ }
+
+ return -1;
+ }
+
+ private static long lookupCompactID(KeyExtent extent, SortedMap<Key,Value> tabletsKeyValues) {
+ Text row = extent.getMetadataEntry();
+ for (Entry<Key,Value> entry : tabletsKeyValues.entrySet()) {
+ Key key = entry.getKey();
+ if (key.getRow().equals(row) && TabletsSection.ServerColumnFamily.COMPACT_COLUMN.equals(key.getColumnFamily(), key.getColumnQualifier()))
+ return Long.parseLong(entry.getValue().toString());
+ }
+
+ return -1;
+ }
+
+ private static TServerInstance lookupLastServer(KeyExtent extent, SortedMap<Key,Value> tabletsKeyValues) {
+ for (Entry<Key,Value> entry : tabletsKeyValues.entrySet()) {
+ if (entry.getKey().getColumnFamily().compareTo(TabletsSection.LastLocationColumnFamily.NAME) == 0) {
+ return new TServerInstance(entry.getValue(), entry.getKey().getColumnQualifier());
+ }
+ }
+ return null;
+ }
+
+ public Tablet(TabletServer tabletServer, KeyExtent extent, Text location, TabletResourceManager trm, SortedMap<Key,Value> tabletsKeyValues)
+ throws IOException {
+ this(tabletServer, extent, location, trm, lookupLogEntries(extent, tabletsKeyValues), lookupDatafiles(tabletServer.getConfiguration(),
+ tabletServer.getFileSystem(), extent, tabletsKeyValues), lookupTime(tabletServer.getConfiguration(), extent, tabletsKeyValues), lookupLastServer(
+ extent, tabletsKeyValues), lookupScanFiles(extent, tabletsKeyValues, tabletServer.getFileSystem()), lookupFlushID(extent, tabletsKeyValues),
+ lookupCompactID(extent, tabletsKeyValues));
+ }
+
+ /**
+ * yet another constructor - this one allows us to avoid costly lookups into the Metadata table if we already know the files we need - as at split time
+ */
+ private Tablet(final TabletServer tabletServer, final KeyExtent extent, final Text location, final TabletResourceManager trm,
+ final List<LogEntry> rawLogEntries, final SortedMap<FileRef,DataFileValue> rawDatafiles, String time, final TServerInstance lastLocation,
+ Set<FileRef> scanFiles, long initFlushID, long initCompactID) throws IOException {
+
+ TableConfiguration tblConf = tabletServer.getTableConfiguration(extent);
+ if (null == tblConf) {
+ Tables.clearCache(tabletServer.getInstance());
+ tblConf = tabletServer.getTableConfiguration(extent);
+ if (null == tblConf) {
+ // Not guaranteed to be non-null, but should be. A failed load will be re-assigned though..
+ log.warn("Could not get table configuration for " + extent.getTableId().toString());
+ }
+ }
+
+ this.tableConfiguration = tblConf;
+
+ TabletFiles tabletPaths = VolumeUtil.updateTabletVolumes(tabletServer.getLock(), tabletServer.getFileSystem(), extent, new TabletFiles(location.toString(),
+ rawLogEntries, rawDatafiles), ReplicationConfigurationUtil.isEnabled(extent, this.tableConfiguration));
+
+ Path locationPath;
+
+ if (tabletPaths.dir.contains(":")) {
+ locationPath = new Path(tabletPaths.dir.toString());
+ } else {
+ locationPath = tabletServer.getFileSystem().getFullPath(FileType.TABLE, extent.getTableId().toString() + tabletPaths.dir.toString());
+ }
+
+ final List<LogEntry> logEntries = tabletPaths.logEntries;
+ final SortedMap<FileRef,DataFileValue> datafiles = tabletPaths.datafiles;
+
+ this.location = locationPath;
+ this.lastLocation = lastLocation;
+ this.tabletDirectory = tabletPaths.dir;
+
+ this.extent = extent;
+ this.tabletResources = trm;
+
+ this.lastFlushID = initFlushID;
+ this.lastCompactID = initCompactID;
+
+ if (extent.isRootTablet()) {
+ long rtime = Long.MIN_VALUE;
+ for (FileRef ref : datafiles.keySet()) {
+ Path path = ref.path();
+ FileSystem ns = tabletServer.getFileSystem().getVolumeByPath(path).getFileSystem();
+ FileSKVIterator reader = FileOperations.getInstance().openReader(path.toString(), true, ns, ns.getConf(), tabletServer.getTableConfiguration(extent));
+ long maxTime = -1;
+ try {
+
+ while (reader.hasTop()) {
+ maxTime = Math.max(maxTime, reader.getTopKey().getTimestamp());
+ reader.next();
+ }
+
+ } finally {
+ reader.close();
+ }
+
+ if (maxTime > rtime) {
+ time = TabletTime.LOGICAL_TIME_ID + "" + maxTime;
+ rtime = maxTime;
+ }
+ }
+ }
+ if (time == null && datafiles.isEmpty() && extent.equals(RootTable.OLD_EXTENT)) {
+ // recovery... old root tablet has no data, so time doesn't matter:
+ time = TabletTime.LOGICAL_TIME_ID + "" + Long.MIN_VALUE;
+ }
+
+ this.tabletServer = tabletServer;
+ this.logId = tabletServer.createLogId(extent);
+
+ setupDefaultSecurityLabels(extent);
+
+ tabletMemory = new TabletMemory(this);
+ tabletTime = TabletTime.getInstance(time);
+ persistedTime = tabletTime.getTime();
+
+ tableConfiguration.addObserver(configObserver = new ConfigurationObserver() {
+
+ private void reloadConstraints() {
+ constraintChecker.set(new ConstraintChecker(tableConfiguration));
+ }
+
+ @Override
+ public void propertiesChanged() {
+ reloadConstraints();
+
+ try {
+ setupDefaultSecurityLabels(extent);
+ } catch (Exception e) {
+ log.error("Failed to reload default security labels for extent: " + extent.toString());
+ }
+ }
+
+ @Override
+ public void propertyChanged(String prop) {
+ if (prop.startsWith(Property.TABLE_CONSTRAINT_PREFIX.getKey()))
+ reloadConstraints();
+ else if (prop.equals(Property.TABLE_DEFAULT_SCANTIME_VISIBILITY.getKey())) {
+ try {
+ log.info("Default security labels changed for extent: " + extent.toString());
+ setupDefaultSecurityLabels(extent);
+ } catch (Exception e) {
+ log.error("Failed to reload default security labels for extent: " + extent.toString());
+ }
+ }
+
+ }
+
+ @Override
+ public void sessionExpired() {
+ log.debug("Session expired, no longer updating per table props...");
+ }
+
+ });
+
+ tableConfiguration.getNamespaceConfiguration().addObserver(configObserver);
+
+ // Force a load of any per-table properties
+ configObserver.propertiesChanged();
+
+ if (!logEntries.isEmpty()) {
+ log.info("Starting Write-Ahead Log recovery for " + this.extent);
+ // count[0] = entries used on tablet
+ // count[1] = track max time from walog entries wihtout timestamps
+ final long[] count = new long[2];
+ final CommitSession commitSession = getTabletMemory().getCommitSession();
+ count[1] = Long.MIN_VALUE;
+ try {
+ Set<String> absPaths = new HashSet<String>();
+ for (FileRef ref : datafiles.keySet())
+ absPaths.add(ref.path().toString());
+
+ tabletServer.recover(this.getTabletServer().getFileSystem(), extent, tableConfiguration, logEntries, absPaths, new MutationReceiver() {
+ @Override
+ public void receive(Mutation m) {
+ // LogReader.printMutation(m);
+ Collection<ColumnUpdate> muts = m.getUpdates();
+ for (ColumnUpdate columnUpdate : muts) {
+ if (!columnUpdate.hasTimestamp()) {
+ // if it is not a user set timestamp, it must have been set
+ // by the system
+ count[1] = Math.max(count[1], columnUpdate.getTimestamp());
+ }
+ }
+ getTabletMemory().mutate(commitSession, Collections.singletonList(m));
+ count[0]++;
+ }
+ });
+
+ if (count[1] != Long.MIN_VALUE) {
+ tabletTime.useMaxTimeFromWALog(count[1]);
+ }
+ commitSession.updateMaxCommittedTime(tabletTime.getTime());
+
+ if (count[0] == 0) {
+ log.debug("No replayed mutations applied, removing unused entries for " + extent);
+ MetadataTableUtil.removeUnusedWALEntries(extent, logEntries, tabletServer.getLock());
+
+ // Ensure that we write a record marking each WAL as requiring replication to make sure we don't abandon the data
+ if (ReplicationConfigurationUtil.isEnabled(extent, tabletServer.getTableConfiguration(extent))) {
+ Status status = StatusUtil.fileClosed();
+ for (LogEntry logEntry : logEntries) {
+ log.debug("Writing closed status to metadata table for " + logEntry.logSet + " " + ProtobufUtil.toString(status));
+ ReplicationTableUtil.updateFiles(SystemCredentials.get(), extent, logEntry.logSet, status);
+ }
+ }
+
+ logEntries.clear();
+ } else if (ReplicationConfigurationUtil.isEnabled(extent, tabletServer.getTableConfiguration(extent))) {
+ // The logs are about to be re-used, we need to record that they have data for this extent,
+ // but that they may get more data
+ Status status = StatusUtil.openWithUnknownLength();
+ for (LogEntry logEntry : logEntries) {
+ log.debug("Writing updated status to metadata table for " + logEntry.logSet + " " + ProtobufUtil.toString(status));
+ ReplicationTableUtil.updateFiles(SystemCredentials.get(), extent, logEntry.logSet, status);
+ }
+ }
+
+ } catch (Throwable t) {
+ if (tableConfiguration.getBoolean(Property.TABLE_FAILURES_IGNORE)) {
+ log.warn("Error recovering from log files: ", t);
+ } else {
+ throw new RuntimeException(t);
+ }
+ }
+ // make some closed references that represent the recovered logs
+ currentLogs = new HashSet<DfsLogger>();
+ for (LogEntry logEntry : logEntries) {
+ for (String log : logEntry.logSet) {
+ currentLogs.add(new DfsLogger(tabletServer.getServerConfig(), log, logEntry.getColumnQualifier().toString()));
+ }
+ }
+
+ log.info("Write-Ahead Log recovery complete for " + this.extent + " (" + count[0] + " mutations applied, " + getTabletMemory().getNumEntries()
+ + " entries created)");
+ }
+
+ String contextName = tableConfiguration.get(Property.TABLE_CLASSPATH);
+ if (contextName != null && !contextName.equals("")) {
+ // initialize context classloader, instead of possibly waiting for it to initialize for a scan
+ // TODO this could hang, causing other tablets to fail to load - ACCUMULO-1292
+ AccumuloVFSClassLoader.getContextManager().getClassLoader(contextName);
+ }
+
+ // do this last after tablet is completely setup because it
+ // could cause major compaction to start
+ datafileManager = new DatafileManager(this, datafiles);
+
+ computeNumEntries();
+
+ getDatafileManager().removeFilesAfterScan(scanFiles);
+
+ // look for hints of a failure on the previous tablet server
+ if (!logEntries.isEmpty() || needsMajorCompaction(MajorCompactionReason.NORMAL)) {
+ // look for any temp files hanging around
+ removeOldTemporaryFiles();
+ }
+
+ log.log(TLevel.TABLET_HIST, extent + " opened");
+ }
+
+ private void removeOldTemporaryFiles() {
+ // remove any temporary files created by a previous tablet server
+ try {
+ for (FileStatus tmp : getTabletServer().getFileSystem().globStatus(new Path(location, "*_tmp"))) {
+ try {
+ log.debug("Removing old temp file " + tmp.getPath());
+ getTabletServer().getFileSystem().delete(tmp.getPath());
+ } catch (IOException ex) {
+ log.error("Unable to remove old temp file " + tmp.getPath() + ": " + ex);
+ }
+ }
+ } catch (IOException ex) {
+ log.error("Error scanning for old temp files in " + location);
+ }
+ }
+
+ private void setupDefaultSecurityLabels(KeyExtent extent) {
+ if (extent.isMeta()) {
+ defaultSecurityLabel = new byte[0];
+ } else {
+ try {
+ ColumnVisibility cv = new ColumnVisibility(tableConfiguration.get(Property.TABLE_DEFAULT_SCANTIME_VISIBILITY));
+ this.defaultSecurityLabel = cv.getExpression();
+ } catch (Exception e) {
+ log.error(e, e);
+ this.defaultSecurityLabel = new byte[0];
+ }
+ }
+ }
+
+ private LookupResult lookup(SortedKeyValueIterator<Key,Value> mmfi, List<Range> ranges, HashSet<Column> columnSet, List<KVEntry> results, long maxResultsSize)
+ throws IOException {
+
+ LookupResult lookupResult = new LookupResult();
+
+ boolean exceededMemoryUsage = false;
+ boolean tabletClosed = false;
+
+ Set<ByteSequence> cfset = null;
+ if (columnSet.size() > 0)
+ cfset = LocalityGroupUtil.families(columnSet);
+
+ for (Range range : ranges) {
+
+ if (exceededMemoryUsage || tabletClosed) {
+ lookupResult.unfinishedRanges.add(range);
+ continue;
+ }
+
+ int entriesAdded = 0;
+
+ try {
+ if (cfset != null)
+ mmfi.seek(range, cfset, true);
+ else
+ mmfi.seek(range, LocalityGroupUtil.EMPTY_CF_SET, false);
+
+ while (mmfi.hasTop()) {
+ Key key = mmfi.getTopKey();
+
+ KVEntry kve = new KVEntry(key, mmfi.getTopValue());
+ results.add(kve);
+ entriesAdded++;
+ lookupResult.bytesAdded += kve.estimateMemoryUsed();
+ lookupResult.dataSize += kve.numBytes();
+
+ exceededMemoryUsage = lookupResult.bytesAdded > maxResultsSize;
+
+ if (exceededMemoryUsage) {
+ addUnfinishedRange(lookupResult, range, key, false);
+ break;
+ }
+
+ mmfi.next();
+ }
+
+ } catch (TooManyFilesException tmfe) {
+ // treat this as a closed tablet, and let the client retry
+ log.warn("Tablet " + getExtent() + " has too many files, batch lookup can not run");
+ handleTabletClosedDuringScan(results, lookupResult, exceededMemoryUsage, range, entriesAdded);
+ tabletClosed = true;
+ } catch (IOException ioe) {
+ if (shutdownInProgress()) {
+ // assume HDFS shutdown hook caused this exception
+ log.debug("IOException while shutdown in progress ", ioe);
+ handleTabletClosedDuringScan(results, lookupResult, exceededMemoryUsage, range, entriesAdded);
+ tabletClosed = true;
+ } else {
+ throw ioe;
+ }
+ } catch (IterationInterruptedException iie) {
+ if (isClosed()) {
+ handleTabletClosedDuringScan(results, lookupResult, exceededMemoryUsage, range, entriesAdded);
+ tabletClosed = true;
+ } else {
+ throw iie;
+ }
+ } catch (TabletClosedException tce) {
+ handleTabletClosedDuringScan(results, lookupResult, exceededMemoryUsage, range, entriesAdded);
+ tabletClosed = true;
+ }
+
+ }
+
+ return lookupResult;
+ }
+
+ private void handleTabletClosedDuringScan(List<KVEntry> results, LookupResult lookupResult, boolean exceededMemoryUsage, Range range, int entriesAdded) {
+ if (exceededMemoryUsage)
+ throw new IllegalStateException("tablet should not exceed memory usage or close, not both");
+
+ if (entriesAdded > 0)
+ addUnfinishedRange(lookupResult, range, results.get(results.size() - 1).getKey(), false);
+ else
+ lookupResult.unfinishedRanges.add(range);
+
+ lookupResult.closed = true;
+ }
+
+ private void addUnfinishedRange(LookupResult lookupResult, Range range, Key key, boolean inclusiveStartKey) {
+ if (range.getEndKey() == null || key.compareTo(range.getEndKey()) < 0) {
+ Range nlur = new Range(new Key(key), inclusiveStartKey, range.getEndKey(), range.isEndKeyInclusive());
+ lookupResult.unfinishedRanges.add(nlur);
+ }
+ }
+
+ public LookupResult lookup(List<Range> ranges, HashSet<Column> columns, Authorizations authorizations, List<KVEntry> results, long maxResultSize,
+ List<IterInfo> ssiList, Map<String,Map<String,String>> ssio, AtomicBoolean interruptFlag) throws IOException {
+
+ if (ranges.size() == 0) {
+ return new LookupResult();
+ }
+
+ ranges = Range.mergeOverlapping(ranges);
+ Collections.sort(ranges);
+
+ Range tabletRange = extent.toDataRange();
+ for (Range range : ranges) {
+ // do a test to see if this range falls within the tablet, if it does not
+ // then clip will throw an exception
+ tabletRange.clip(range);
+ }
+
+ ScanDataSource dataSource = new ScanDataSource(this, authorizations, this.defaultSecurityLabel, columns, ssiList, ssio, interruptFlag);
+
+ LookupResult result = null;
+
+ try {
+ SortedKeyValueIterator<Key,Value> iter = new SourceSwitchingIterator(dataSource);
+ result = lookup(iter, ranges, columns, results, maxResultSize);
+ return result;
+ } catch (IOException ioe) {
+ dataSource.close(true);
+ throw ioe;
+ } finally {
+ // code in finally block because always want
+ // to return mapfiles, even when exception is thrown
+ dataSource.close(false);
+
+ synchronized (this) {
+ queryCount += results.size();
+ if (result != null)
+ queryBytes += result.dataSize;
+ }
+ }
+ }
+
+ Batch nextBatch(SortedKeyValueIterator<Key,Value> iter, Range range, int num, Set<Column> columns) throws IOException {
+
+ // log.info("In nextBatch..");
+
+ List<KVEntry> results = new ArrayList<KVEntry>();
+ Key key = null;
+
+ Value value;
+ long resultSize = 0L;
+ long resultBytes = 0L;
+
+ long maxResultsSize = tableConfiguration.getMemoryInBytes(Property.TABLE_SCAN_MAXMEM);
+
+ if (columns.size() == 0) {
+ iter.seek(range, LocalityGroupUtil.EMPTY_CF_SET, false);
+ } else {
+ iter.seek(range, LocalityGroupUtil.families(columns), true);
+ }
+
+ Key continueKey = null;
+ boolean skipContinueKey = false;
+
+ boolean endOfTabletReached = false;
+ while (iter.hasTop()) {
+
+ value = iter.getTopValue();
+ key = iter.getTopKey();
+
+ KVEntry kvEntry = new KVEntry(key, value); // copies key and value
+ results.add(kvEntry);
+ resultSize += kvEntry.estimateMemoryUsed();
+ resultBytes += kvEntry.numBytes();
+
+ if (resultSize >= maxResultsSize || results.size() >= num) {
+ continueKey = new Key(key);
+ skipContinueKey = true;
+ break;
+ }
+
+ iter.next();
+ }
+
+ if (iter.hasTop() == false) {
+ endOfTabletReached = true;
+ }
+
+ if (endOfTabletReached) {
+ continueKey = null;
+ }
+
+ if (endOfTabletReached && results.size() == 0)
+ results = null;
+
+ return new Batch(skipContinueKey, results, continueKey, resultBytes);
+ }
+
+ /**
+ * Determine if a JVM shutdown is in progress.
+ *
+ */
+ boolean shutdownInProgress() {
+ try {
+ Runtime.getRuntime().removeShutdownHook(new Thread(new Runnable() {
+ @Override
+ public void run() {}
+ }));
+ } catch (IllegalStateException ise) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public Scanner createScanner(Range range, int num, Set<Column> columns, Authorizations authorizations, List<IterInfo> ssiList,
+ Map<String,Map<String,String>> ssio, boolean isolated, AtomicBoolean interruptFlag) {
+ // do a test to see if this range falls within the tablet, if it does not
+ // then clip will throw an exception
+ extent.toDataRange().clip(range);
+
+ ScanOptions opts = new ScanOptions(num, authorizations, this.defaultSecurityLabel, columns, ssiList, ssio, interruptFlag, isolated);
+ return new Scanner(this, range, opts);
+ }
+
+ DataFileValue minorCompact(VolumeManager fs, InMemoryMap memTable, FileRef tmpDatafile, FileRef newDatafile, FileRef mergeFile, boolean hasQueueTime,
+ long queued, CommitSession commitSession, long flushId, MinorCompactionReason mincReason) {
+ boolean failed = false;
+ long start = System.currentTimeMillis();
+ timer.incrementStatusMinor();
+
+ long count = 0;
+
+ try {
+ Span span = Trace.start("write");
+ CompactionStats stats;
+ try {
+ count = memTable.getNumEntries();
+
+ DataFileValue dfv = null;
+ if (mergeFile != null)
+ dfv = getDatafileManager().getDatafileSizes().get(mergeFile);
+
+ MinorCompactor compactor = new MinorCompactor(this, memTable, mergeFile, dfv, tmpDatafile, mincReason, tableConfiguration);
+ stats = compactor.call();
+ } finally {
+ span.stop();
+ }
+ span = Trace.start("bringOnline");
+ try {
+ getDatafileManager().bringMinorCompactionOnline(tmpDatafile, newDatafile, mergeFile, new DataFileValue(stats.getFileSize(), stats.getEntriesWritten()),
+ commitSession, flushId);
+ } finally {
+ span.stop();
+ }
+ return new DataFileValue(stats.getFileSize(), stats.getEntriesWritten());
+ } catch (Exception e) {
+ failed = true;
+ throw new RuntimeException(e);
+ } catch (Error e) {
+ // Weird errors like "OutOfMemoryError" when trying to create the thread for the compaction
+ failed = true;
+ throw new RuntimeException(e);
+ } finally {
+ try {
+ getTabletMemory().finalizeMinC();
+ } catch (Throwable t) {
+ log.error("Failed to free tablet memory", t);
+ }
+
+ if (!failed) {
+ lastMinorCompactionFinishTime = System.currentTimeMillis();
+ }
+ TabletServerMinCMetrics minCMetrics = getTabletServer().getMinCMetrics();
+ if (minCMetrics.isEnabled())
+ minCMetrics.add(TabletServerMinCMetrics.minc, (lastMinorCompactionFinishTime - start));
+ if (hasQueueTime) {
+ timer.updateTime(Operation.MINOR, queued, start, count, failed);
+ if (minCMetrics.isEnabled())
+ minCMetrics.add(TabletServerMinCMetrics.queue, (start - queued));
+ } else
+ timer.updateTime(Operation.MINOR, start, count, failed);
+ }
+ }
+
+ private synchronized MinorCompactionTask prepareForMinC(long flushId, MinorCompactionReason mincReason) {
+ CommitSession oldCommitSession = getTabletMemory().prepareForMinC();
+ otherLogs = currentLogs;
+ currentLogs = new HashSet<DfsLogger>();
+
+ FileRef mergeFile = null;
+ if (mincReason != MinorCompactionReason.RECOVERY) {
+ mergeFile = getDatafileManager().reserveMergingMinorCompactionFile();
+ }
+
+ return new MinorCompactionTask(this, mergeFile, oldCommitSession, flushId, mincReason);
+
+ }
+
+ public void flush(long tableFlushID) {
+ boolean updateMetadata = false;
+ boolean initiateMinor = false;
+
+ try {
+
+ synchronized (this) {
+
+ // only want one thing at a time to update flush ID to ensure that metadata table and tablet in memory state are consistent
+ if (updatingFlushID)
+ return;
+
+ if (lastFlushID >= tableFlushID)
+ return;
+
+ if (isClosing() || isClosed() || getTabletMemory().memoryReservedForMinC())
+ return;
+
+ if (getTabletMemory().getMemTable().getNumEntries() == 0) {
+ lastFlushID = tableFlushID;
+ updatingFlushID = true;
+ updateMetadata = true;
+ } else
+ initiateMinor = true;
+ }
+
+ if (updateMetadata) {
+ Credentials creds = SystemCredentials.get();
+ // if multiple threads were allowed to update this outside of a sync block, then it would be
+ // a race condition
+ MetadataTableUtil.updateTabletFlushID(extent, tableFlushID, creds, getTabletServer().getLock());
+ } else if (initiateMinor)
+ initiateMinorCompaction(tableFlushID, MinorCompactionReason.USER);
+
+ } finally {
+ if (updateMetadata) {
+ synchronized (this) {
+ updatingFlushID = false;
+ this.notifyAll();
+ }
+ }
+ }
+
+ }
+
+ public boolean initiateMinorCompaction(MinorCompactionReason mincReason) {
+ if (isClosed()) {
+ // don't bother trying to get flush id if closed... could be closed after this check but that is ok... just trying to cut down on uneeded log messages....
+ return false;
+ }
+
+ // get the flush id before the new memmap is made available for write
+ long flushId;
+ try {
+ flushId = getFlushID();
+ } catch (NoNodeException e) {
+ log.info("Asked to initiate MinC when there was no flush id " + getExtent() + " " + e.getMessage());
+ return false;
+ }
+ return initiateMinorCompaction(flushId, mincReason);
+ }
+
+ public boolean minorCompactNow(MinorCompactionReason mincReason) {
+ long flushId;
+ try {
+ flushId = getFlushID();
+ } catch (NoNodeException e) {
+ log.info("Asked to initiate MinC when there was no flush id " + getExtent() + " " + e.getMessage());
+ return false;
+ }
+ MinorCompactionTask mct = createMinorCompactionTask(flushId, mincReason);
+ if (mct == null)
+ return false;
+ mct.run();
+ return true;
+ }
+
+ boolean initiateMinorCompaction(long flushId, MinorCompactionReason mincReason) {
+ MinorCompactionTask mct = createMinorCompactionTask(flushId, mincReason);
+ if (mct == null)
+ return false;
+ getTabletResources().executeMinorCompaction(mct);
+ return true;
+ }
+
+ private MinorCompactionTask createMinorCompactionTask(long flushId, MinorCompactionReason mincReason) {
+ MinorCompactionTask mct;
+ long t1, t2;
+
+ StringBuilder logMessage = null;
+
+ try {
+ synchronized (this) {
+ t1 = System.currentTimeMillis();
+
+ if (isClosing() || isClosed() || majorCompactionState == CompactionState.WAITING_TO_START || getTabletMemory().memoryReservedForMinC()
+ || getTabletMemory().getMemTable().getNumEntries() == 0 || updatingFlushID) {
+
+ logMessage = new StringBuilder();
+
+ logMessage.append(extent.toString());
+ logMessage.append(" closeState " + closeState);
+ logMessage.append(" majorCompactionState " + majorCompactionState);
+ if (getTabletMemory() != null)
+ logMessage.append(" tabletMemory.memoryReservedForMinC() " + getTabletMemory().memoryReservedForMinC());
+ if (getTabletMemory() != null && getTabletMemory().getMemTable() != null)
+ logMessage.append(" tabletMemory.getMemTable().getNumEntries() " + getTabletMemory().getMemTable().getNumEntries());
+ logMessage.append(" updatingFlushID " + updatingFlushID);
+
+ return null;
+ }
+
+ mct = prepareForMinC(flushId, mincReason);
+ t2 = System.currentTimeMillis();
+ }
+ } finally {
+ // log outside of sync block
+ if (logMessage != null && log.isDebugEnabled())
+ log.debug(logMessage);
+ }
+
+ log.debug(String.format("MinC initiate lock %.2f secs", (t2 - t1) / 1000.0));
+ return mct;
+ }
+
+ public long getFlushID() throws NoNodeException {
+ try {
+ String zTablePath = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + extent.getTableId()
+ + Constants.ZTABLE_FLUSH_ID;
- return Long.parseLong(new String(ZooReaderWriter.getRetryingInstance().getData(zTablePath, null), StandardCharsets.UTF_8));
++ return Long.parseLong(new String(ZooReaderWriter.getInstance().getData(zTablePath, null), StandardCharsets.UTF_8));
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } catch (NumberFormatException nfe) {
+ throw new RuntimeException(nfe);
+ } catch (KeeperException ke) {
+ if (ke instanceof NoNodeException) {
+ throw (NoNodeException) ke;
+ } else {
+ throw new RuntimeException(ke);
+ }
+ }
+ }
+
+ long getCompactionCancelID() {
+ String zTablePath = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + extent.getTableId()
+ + Constants.ZTABLE_COMPACT_CANCEL_ID;
+
+ try {
- return Long.parseLong(new String(ZooReaderWriter.getRetryingInstance().getData(zTablePath, null), StandardCharsets.UTF_8));
++ return Long.parseLong(new String(ZooReaderWriter.getInstance().getData(zTablePath, null), StandardCharsets.UTF_8));
+ } catch (KeeperException e) {
+ throw new RuntimeException(e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Pair<Long,List<IteratorSetting>> getCompactionID() throws NoNodeException {
+ try {
+ String zTablePath = Constants.ZROOT + "/" + HdfsZooInstance.getInstance().getInstanceID() + Constants.ZTABLES + "/" + extent.getTableId()
+ + Constants.ZTABLE_COMPACT_ID;
+
- String[] tokens = new String(ZooReaderWriter.getRetryingInstance().getData(zTablePath, null), StandardCharsets.UTF_8).split(",");
++ String[] tokens = new String(ZooReaderWriter.getInstance().getData(zTablePath, null), StandardCharsets.UTF_8).split(",");
+ long compactID = Long.parseLong(tokens[0]);
+
+ CompactionIterators iters = new CompactionIterators();
+
+ if (tokens.length > 1) {
+ Hex hex = new Hex();
+ ByteArrayInputStream bais = new ByteArrayInputStream(hex.decode(tokens[1].split("=")[1].getBytes(StandardCharsets.UTF_8)));
+ DataInputStream dis = new DataInputStream(bais);
+
+ try {
+ iters.readFields(dis);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ KeyExtent ke = new KeyExtent(extent.getTableId(), iters.getEndRow(), iters.getStartRow());
+
+ if (!ke.overlaps(extent)) {
+ // only use iterators if compaction range overlaps
+ iters = new CompactionIterators();
+ }
+ }
+
+ return new Pair<Long,List<IteratorSetting>>(compactID, iters.getIterators());
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } catch (NumberFormatException nfe) {
+ throw new RuntimeException(nfe);
+ } catch (KeeperException ke) {
+ if (ke instanceof NoNodeException) {
+ throw (NoNodeException) ke;
+ } else {
+ throw new RuntimeException(ke);
+ }
+ } catch (DecoderException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public synchronized void waitForMinC() {
+ getTabletMemory().waitForMinC();
+ }
+
+ private synchronized CommitSession finishPreparingMutations(long time) {
+ if (writesInProgress < 0) {
+ throw new IllegalStateException("waitingForLogs < 0 " + writesInProgress);
+ }
+
+ if (isClosed() || getTabletMemory() == null) {
+ return null;
+ }
+
+ writesInProgress++;
+ CommitSession commitSession = getTabletMemory().getCommitSession();
+ commitSession.incrementCommitsInProgress();
+ commitSession.updateMaxCommittedTime(time);
+ return commitSession;
+ }
+
+ public void checkConstraints() {
+ ConstraintChecker cc = constraintChecker.get();
+
+ if (cc.classLoaderChanged()) {
+ ConstraintChecker ncc = new ConstraintChecker(tableConfiguration);
+ constraintChecker.compareAndSet(cc, ncc);
+ }
+ }
+
+ public CommitSession prepareMutationsForCommit(TservConstraintEnv cenv, List<Mutation> mutations) throws TConstraintViolationException {
+
+ ConstraintChecker cc = constraintChecker.get();
+
+ List<Mutation> violators = null;
+ Violations violations = new Violations();
+ cenv.setExtent(extent);
+ for (Mutation mutation : mutations) {
+ Violations more = cc.check(cenv, mutation);
+ if (more != null) {
+ violations.add(more);
+ if (violators == null)
+ violators = new ArrayList<Mutation>();
+ violators.add(mutation);
+ }
+ }
+
+ long time = tabletTime.setUpdateTimes(mutations);
+
+ if (!violations.isEmpty()) {
+
+ HashSet<Mutation> violatorsSet = new HashSet<Mutation>(violators);
+ ArrayList<Mutation> nonViolators = new ArrayList<Mutation>();
+
+ for (Mutation mutation : mutations) {
+ if (!violatorsSet.contains(mutation)) {
+ nonViolators.add(mutation);
+ }
+ }
+
+ CommitSession commitSession = null;
+
+ if (nonViolators.size() > 0) {
+ // if everything is a violation, then it is expected that
+ // code calling this will not log or commit
+ commitSession = finishPreparingMutations(time);
+ if (commitSession == null)
+ return null;
+ }
+
+ throw new TConstraintViolationException(violations, violators, nonViolators, commitSession);
+ }
+
+ return finishPreparingMutations(time);
+ }
+
+ @Override
+ public synchronized void abortCommit(CommitSession commitSession, List<Mutation> value) {
+ if (writesInProgress <= 0) {
+ throw new IllegalStateException("waitingForLogs <= 0 " + writesInProgress);
+ }
+
+ if (isCloseComplete() || getTabletMemory() == null) {
+ throw new IllegalStateException("aborting commit when tablet is closed");
+ }
+
+ commitSession.decrementCommitsInProgress();
+ writesInProgress--;
+ if (writesInProgress == 0)
+ this.notifyAll();
+ }
+
+ @Override
+ public void commit(CommitSession commitSession, List<Mutation> mutations) {
+
+ int totalCount = 0;
+ long totalBytes = 0;
+
+ // write the mutation to the in memory table
+ for (Mutation mutation : mutations) {
+ totalCount += mutation.size();
+ totalBytes += mutation.numBytes();
+ }
+
+ getTabletMemory().mutate(commitSession, mutations);
+
+ synchronized (this) {
+ if (writesInProgress < 1) {
+ throw new IllegalStateException("commiting mutations after logging, but not waiting for any log messages");
+ }
+
+ if (isCloseComplete()) {
+ throw new IllegalStateException("tablet closed with outstanding messages to the logger");
+ }
+
+ getTabletMemory().updateMemoryUsageStats();
+
+ // decrement here in case an exception is thrown below
+ writesInProgress--;
+ if (writesInProgress == 0)
+ this.notifyAll();
+
+ commitSession.decrementCommitsInProgress();
+
+ numEntries += totalCount;
+ numEntriesInMemory += totalCount;
+ ingestCount += totalCount;
+ ingestBytes += totalBytes;
+ }
+ }
+
+ /**
+ * Closes the mapfiles associated with a Tablet. If saveState is true, a minor compaction is performed.
+ */
+ public void close(boolean saveState) throws IOException {
+ initiateClose(saveState, false, false);
+ completeClose(saveState, true);
+ }
+
+ void initiateClose(boolean saveState, boolean queueMinC, boolean disableWrites) {
+
+ if (!saveState && queueMinC) {
+ throw new IllegalArgumentException("Not saving state on close and requesting minor compactions queue does not make sense");
+ }
+
+ log.debug("initiateClose(saveState=" + saveState + " queueMinC=" + queueMinC + " disableWrites=" + disableWrites + ") " + getExtent());
+
+ MinorCompactionTask mct = null;
+
+ synchronized (this) {
+ if (isClosed() || isClosing()) {
+ String msg = "Tablet " + getExtent() + " already " + closeState;
+ throw new IllegalStateException(msg);
+ }
+
+ // enter the closing state, no splits, minor, or major compactions can start
+ // should cause running major compactions to stop
+ closeState = CloseState.CLOSING;
+ this.notifyAll();
+
+ // determines if inserts and queries can still continue while minor compacting
+ if (disableWrites) {
+ closeState = CloseState.CLOSED;
+ }
+
+ // wait for major compactions to finish, setting closing to
+ // true should cause any running major compactions to abort
+ while (isMajorCompactionRunning()) {
+ try {
+ this.wait(50);
+ } catch (InterruptedException e) {
+ log.error(e.toString());
+ }
+ }
+
+ while (updatingFlushID) {
+ try {
+ this.wait(50);
+ } catch (InterruptedException e) {
+ log.error(e.toString());
+ }
+ }
+
+ if (!saveState || getTabletMemory().getMemTable().getNumEntries() == 0) {
+ return;
+ }
+
+ getTabletMemory().waitForMinC();
+
+ try {
+ mct = prepareForMinC(getFlushID(), MinorCompactionReason.CLOSE);
+ } catch (NoNodeException e) {
+ throw new RuntimeException(e);
+ }
+
+ if (queueMinC) {
+ getTabletResources().executeMinorCompaction(mct);
+ return;
+ }
+
+ }
+
+ // do minor compaction outside of synch block so that tablet can be read and written to while
+ // compaction runs
+ mct.run();
+ }
+
+ private boolean closeCompleting = false;
+
+ synchronized void completeClose(boolean saveState, boolean completeClose) throws IOException {
+
+ if (!isClosing() || isCloseComplete() || closeCompleting) {
+ throw new IllegalStateException("closeState = " + closeState);
+ }
+
+ log.debug("completeClose(saveState=" + saveState + " completeClose=" + completeClose + ") " + getExtent());
+
+ // ensure this method is only called once, also guards against multiple
+ // threads entering the method at the same time
+ closeCompleting = true;
+ closeState = CloseState.CLOSED;
+
+ // modify dataSourceDeletions so scans will try to switch data sources and fail because the tablet is closed
+ dataSourceDeletions.incrementAndGet();
+
+ for (ScanDataSource activeScan : activeScans) {
+ activeScan.interrupt();
+ }
+
+ // wait for reads and writes to complete
+ while (writesInProgress > 0 || activeScans.size() > 0) {
+ try {
+ this.wait(50);
+ } catch (InterruptedException e) {
+ log.error(e.toString());
+ }
+ }
+
+ getTabletMemory().waitForMinC();
+
+ if (saveState && getTabletMemory().getMemTable().getNumEntries() > 0) {
+ try {
+ prepareForMinC(getFlushID(), MinorCompactionReason.CLOSE).run();
+ } catch (NoNodeException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ if (saveState) {
+ // at this point all tablet data is flushed, so do a consistency check
+ RuntimeException err = null;
+ for (int i = 0; i < 5; i++) {
+ try {
+ closeConsistencyCheck();
+ err = null;
+ } catch (RuntimeException t) {
+ err = t;
+ log.error("Consistency check fails, retrying " + t);
+ UtilWaitThread.sleep(500);
+ }
+ }
+ if (err != null) {
+ ProblemReports.getInstance().report(new ProblemReport(extent.getTableId().toString(), ProblemType.TABLET_LOAD, this.extent.toString(), err));
+ log.error("Tablet closed consistency check has failed for " + this.extent + " giving up and closing");
+ }
+ }
+
+ try {
+ getTabletMemory().getMemTable().delete(0);
+ } catch (Throwable t) {
+ log.error("Failed to delete mem table : " + t.getMessage(), t);
+ }
+
+ getTabletMemory().close();
+
+ // close map files
+ getTabletResources().close();
+
+ log.log(TLevel.TABLET_HIST, extent + " closed");
+
+ tableConfiguration.getNamespaceConfiguration().removeObserver(configObserver);
+ tableConfiguration.removeObserver(configObserver);
+
+ if (completeClose)
+ closeState = CloseState.COMPLETE;
+ }
+
+ private void closeConsistencyCheck() {
+
+ if (getTabletMemory().getMemTable().getNumEntries() != 0) {
+ String msg = "Closed tablet " + extent + " has " + getTabletMemory().getMemTable().getNumEntries() + " entries in memory";
+ log.error(msg);
+ throw new RuntimeException(msg);
+ }
+
+ if (getTabletMemory().memoryReservedForMinC()) {
+ String msg = "Closed tablet " + extent + " has minor compacting memory";
+ log.error(msg);
+ throw new RuntimeException(msg);
+ }
+
+ try {
+ Pair<List<LogEntry>,SortedMap<FileRef,DataFileValue>> fileLog = MetadataTableUtil.getFileAndLogEntries(SystemCredentials.get(), extent);
+
+ if (fileLog.getFirst().size() != 0) {
+ String msg = "Closed tablet " + extent + " has walog entries in " + MetadataTable.NAME + " " + fileLog.getFirst();
+ log.error(msg);
+ throw new RuntimeException(msg);
+ }
+
+ if (extent.isRootTablet()) {
+ if (!fileLog.getSecond().keySet().equals(getDatafileManager().getDatafileSizes().keySet())) {
+ String msg = "Data file in " + RootTable.NAME + " differ from in memory data " + extent + " " + fileLog.getSecond().keySet() + " "
+ + getDatafileManager().getDatafileSizes().keySet();
+ log.error(msg);
+ throw new RuntimeException(msg);
+ }
+ } else {
+ if (!fileLog.getSecond().equals(getDatafileManager().getDatafileSizes())) {
+ String msg = "Data file in " + MetadataTable.NAME + " differ from in memory data " + extent + " " + fileLog.getSecond() + " "
+ + getDatafileManager().getDatafileSizes();
+ log.error(msg);
+ throw new RuntimeException(msg);
+ }
+ }
+
+ } catch (Exception e) {
+ String msg = "Failed to do close consistency check for tablet " + extent;
+ log.error(msg, e);
+ throw new RuntimeException(msg, e);
+
+ }
+
+ if (otherLogs.size() != 0 || currentLogs.size() != 0) {
+ String msg = "Closed tablet " + extent + " has walog entries in memory currentLogs = " + currentLogs + " otherLogs = " + otherLogs;
+ log.error(msg);
+ throw new RuntimeException(msg);
+ }
+
+ // TODO check lastFlushID and lostCompactID - ACCUMULO-1290
+ }
+
+ /**
+ * Returns a Path object representing the tablet's location on the DFS.
+ *
+ * @return location
+ */
+ public Path getLocation() {
+ return location;
+ }
+
+ public synchronized boolean initiateMajorCompaction(MajorCompactionReason reason) {
+
+ if (isClosing() || isClosed() || !needsMajorCompaction(reason) || isMajorCompactionRunning() || majorCompactionQueued.contains(reason)) {
+ return false;
+ }
+
+ majorCompactionQueued.add(reason);
+
+ getTabletResources().executeMajorCompaction(getExtent(), new CompactionRunner(this, reason));
+
+ return false;
+ }
+
+ /**
+ * Returns true if a major compaction should be performed on the tablet.
+ *
+ */
+ public boolean needsMajorCompaction(MajorCompactionReason reason) {
+ if (isMajorCompactionRunning())
+ return false;
+ if (reason == MajorCompactionReason.CHOP || reason == MajorCompactionReason.USER)
+ return true;
+ return getTabletResources().needsMajorCompaction(getDatafileManager().getDatafileSizes(), reason);
+ }
+
+ /**
+ * Returns an int representing the total block size of the files served by this tablet.
+ *
+ * @return size
+ */
+ // this is the size of just the files
+ public long estimateTabletSize() {
+ long size = 0L;
+
+ for (DataFileValue sz : getDatafileManager().getDatafileSizes().values())
+ size += sz.getSize();
+
+ return size;
+ }
+
+ private boolean sawBigRow = false;
+ private long timeOfLastMinCWhenBigFreakinRowWasSeen = 0;
+ private long timeOfLastImportWhenBigFreakinRowWasSeen = 0;
+ private long splitCreationTime;
+
+ private SplitRowSpec findSplitRow(Collection<FileRef> files) {
+
+ // never split the root tablet
+ // check if we already decided that we can never split
+ // check to see if we're big enough to split
+
+ long splitThreshold = tableConfiguration.getMemoryInBytes(Property.TABLE_SPLIT_THRESHOLD);
+ long maxEndRow = tableConfiguration.getMemoryInBytes(Property.TABLE_MAX_END_ROW_SIZE);
+
+ if (extent.isRootTablet() || estimateTabletSize() <= splitThreshold) {
+ return null;
+ }
+
+ // have seen a big row before, do not bother checking unless a minor compaction or map file import has occurred.
+ if (sawBigRow) {
+ if (timeOfLastMinCWhenBigFreakinRowWasSeen != lastMinorCompactionFinishTime || timeOfLastImportWhenBigFreakinRowWasSeen != lastMapFileImportTime) {
+ // a minor compaction or map file import has occurred... check again
+ sawBigRow = false;
+ } else {
+ // nothing changed, do not split
+ return null;
+ }
+ }
+
+ SortedMap<Double,Key> keys = null;
+
+ try {
+ // we should make .25 below configurable
+ keys = FileUtil.findMidPoint(getTabletServer().getFileSystem(), getTabletServer().getConfiguration(), extent.getPrevEndRow(), extent.getEndRow(),
+ FileUtil.toPathStrings(files), .25);
+ } catch (IOException e) {
+ log.error("Failed to find midpoint " + e.getMessage());
+ return null;
+ }
+
+ // check to see if one row takes up most of the tablet, in which case we can not split
+ try {
+
+ Text lastRow;
+ if (extent.getEndRow() == null) {
+ Key lastKey = (Key) FileUtil.findLastKey(getTabletServer().getFileSystem(), getTabletServer().getConfiguration(), files);
+ lastRow = lastKey.getRow();
+ } else {
+ lastRow = extent.getEndRow();
+ }
+
+ // We expect to get a midPoint for this set of files. If we don't get one, we have a problem.
+ final Key mid = keys.get(.5);
+ if (null == mid) {
+ throw new IllegalStateException("Could not determine midpoint for files");
+ }
+
+ // check to see that the midPoint is not equal to the end key
+ if (mid.compareRow(lastRow) == 0) {
+ if (keys.firstKey() < .5) {
+ Key candidate = keys.get(keys.firstKey());
+ if (candidate.getLength() > maxEndRow) {
+ log.warn("Cannot split tablet " + extent + ", selected split point too long. Length : " + candidate.getLength());
+
+ sawBigRow = true;
+ timeOfLastMinCWhenBigFreakinRowWasSeen = lastMinorCompactionFinishTime;
+ timeOfLastImportWhenBigFreakinRowWasSeen = lastMapFileImportTime;
+
+ return null;
+ }
+ if (candidate.compareRow(lastRow) != 0) {
+ // we should use this ratio in split size estimations
+ if (log.isTraceEnabled())
+ log.trace(String.format("Splitting at %6.2f instead of .5, row at .5 is same as end row%n", keys.firstKey()));
+ return new SplitRowSpec(keys.firstKey(), candidate.getRow());
+ }
+
+ }
+
+ log.warn("Cannot split tablet " + extent + " it contains a big row : " + lastRow);
+
+ sawBigRow = true;
+ timeOfLastMinCWhenBigFreakinRowWasSeen = lastMinorCompactionFinishTime;
+ timeOfLastImportWhenBigFreakinRowWasSeen = lastMapFileImportTime;
+
+ return null;
+ }
+
+ Text text = mid.getRow();
+ SortedMap<Double,Key> firstHalf = keys.headMap(.5);
+ if (firstHalf.size() > 0) {
+ Text beforeMid = firstHalf.get(firstHalf.lastKey()).getRow();
+ Text shorter = new Text();
+ int trunc = longestCommonLength(text, beforeMid);
+ shorter.set(text.getBytes(), 0, Math.min(text.getLength(), trunc + 1));
+ text = shorter;
+ }
+
+ if (text.getLength() > maxEndRow) {
+ log.warn("Cannot split tablet " + extent + ", selected split point too long. Length : " + text.getLength());
+
+ sawBigRow = true;
+ timeOfLastMinCWhenBigFreakinRowWasSeen = lastMinorCompactionFinishTime;
+ timeOfLastImportWhenBigFreakinRowWasSeen = lastMapFileImportTime;
+
+ return null;
+ }
+
+ return new SplitRowSpec(.5, text);
+ } catch (IOException e) {
+ // don't split now, but check again later
+ log.error("Failed to find lastkey " + e.getMessage());
+ return null;
+ }
+
+ }
+
+ private static int longestCommonLength(Text text, Text beforeMid) {
+ int common = 0;
+ while (common < text.getLength() && common < beforeMid.getLength() && text.getBytes()[common] == beforeMid.getBytes()[common]) {
+ common++;
+ }
+ return common;
+ }
+
+ private Map<FileRef,Pair<Key,Key>> getFirstAndLastKeys(SortedMap<FileRef,DataFileValue> allFiles) throws IOException {
+ Map<FileRef,Pair<Key,Key>> result = new HashMap<FileRef,Pair<Key,Key>>();
+ FileOperations fileFactory = FileOperations.getInstance();
+ VolumeManager fs = getTabletServer().getFileSystem();
+ for (Entry<FileRef,DataFileValue> entry : allFiles.entrySet()) {
+ FileRef file = entry.getKey();
+ FileSystem ns = fs.getVolumeByPath(file.path()).getFileSystem();
+ FileSKVIterator openReader = fileFactory.openReader(file.path().toString(), true, ns, ns.getConf(), this.getTableConfiguration());
+ try {
+ Key first = openReader.getFirstKey();
+ Key last = openReader.getLastKey();
+ result.put(file, new Pair<Key,Key>(first, last));
+ } finally {
+ openReader.close();
+ }
+ }
+ return result;
+ }
+
+ List<FileRef> findChopFiles(KeyExtent extent, Map<FileRef,Pair<Key,Key>> firstAndLastKeys, Collection<FileRef> allFiles) throws IOException {
+ List<FileRef> result = new ArrayList<FileRef>();
+ if (firstAndLastKeys == null) {
+ result.addAll(allFiles);
+ return result;
+ }
+
+ for (FileRef file : allFiles) {
+ Pair<Key,Key> pair = firstAndLastKeys.get(file);
+ if (pair == null) {
+ // file was created or imported after we obtained the first and last keys... there
+ // are a few options here... throw an exception which will cause the compaction to
+ // retry and also cause ugly error message that the admin has to ignore... could
+ // go get the first and last key, but this code is called while the tablet lock
+ // is held... or just compact the file....
+ result.add(file);
+ } else {
+ Key first = pair.getFirst();
+ Key last = pair.getSecond();
+ // If first and last are null, it's an empty file. Add it to the compact set so it goes away.
+ if ((first == null && last == null) || !extent.contains(first.getRow()) || !extent.contains(last.getRow())) {
+ result.add(file);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns true if this tablet needs to be split
+ *
+ */
+ public synchronized boolean needsSplit() {
+ if (isClosing() || isClosed())
+ return false;
+ return findSplitRow(getDatafileManager().getFiles()) != null;
+ }
+
+ // BEGIN PRIVATE METHODS RELATED TO MAJOR COMPACTION
+
+ private boolean isCompactionEnabled() {
+ return !isClosing() && !getTabletServer().isMajorCompactionDisabled();
+ }
+
+ private CompactionStats _majorCompact(MajorCompactionReason reason) throws IOException, CompactionCanceledException {
+
+ long t1, t2, t3;
+
+ // acquire file info outside of tablet lock
+ CompactionStrategy strategy = Property.createTableInstanceFromPropertyName(tableConfiguration, Property.TABLE_COMPACTION_STRATEGY,
+ CompactionStrategy.class, new DefaultCompactionStrategy());
+ strategy.init(Property.getCompactionStrategyOptions(tableConfiguration));
+
+ Map<FileRef,Pair<Key,Key>> firstAndLastKeys = null;
+ if (reason == MajorCompactionReason.CHOP) {
+ firstAndLastKeys = getFirstAndLastKeys(getDatafileManager().getDatafileSizes());
+ } else if (reason != MajorCompactionReason.USER) {
+ MajorCompactionRequest request = new MajorCompactionRequest(extent, reason, getTabletServer().getFileSystem(), tableConfiguration);
+ request.setFiles(getDatafileManager().getDatafileSizes());
+ strategy.gatherInformation(request);
+ }
+
+ Map<FileRef,DataFileValue> filesToCompact;
+
+ int maxFilesToCompact = tableConfiguration.getCount(Property.TSERV_MAJC_THREAD_MAXOPEN);
+
+ CompactionStats majCStats = new CompactionStats();
+ CompactionPlan plan = null;
+
+ boolean propogateDeletes = false;
+
+ synchronized (this) {
+ // plan all that work that needs to be done in the sync block... then do the actual work
+ // outside the sync block
+
+ t1 = System.currentTimeMillis();
+
+ majorCompactionState = CompactionState.WAITING_TO_START;
+
+ getTabletMemory().waitForMinC();
+
+ t2 = System.currentTimeMillis();
+
+ majorCompactionState = CompactionState.IN_PROGRESS;
+ notifyAll();
+
+ VolumeManager fs = getTabletServer().getFileSystem();
+ if (extent.isRootTablet()) {
+ // very important that we call this before doing major compaction,
+ // otherwise deleted compacted files could possible be brought back
+ // at some point if the file they were compacted to was legitimately
+ // removed by a major compaction
+ RootFiles.cleanupReplacement(fs, fs.listStatus(this.location), false);
+ }
+ SortedMap<FileRef,DataFileValue> allFiles = getDatafileManager().getDatafileSizes();
+ List<FileRef> inputFiles = new ArrayList<FileRef>();
+ if (reason == MajorCompactionReason.CHOP) {
+ // enforce rules: files with keys outside our range need to be compacted
+ inputFiles.addAll(findChopFiles(extent, firstAndLastKeys, allFiles.keySet()));
+ } else if (reason == MajorCompactionReason.USER) {
+ inputFiles.addAll(allFiles.keySet());
+ } else {
+ MajorCompactionRequest request = new MajorCompactionRequest(extent, reason, fs, tableConfiguration);
+ request.setFiles(allFiles);
+ plan = strategy.getCompactionPlan(request);
+ if (plan != null) {
+ plan.validate(allFiles.keySet());
+ inputFiles.addAll(plan.inputFiles);
+ }
+ }
+
+ if (inputFiles.isEmpty()) {
+ return majCStats;
+ }
+ // If no original files will exist at the end of the compaction, we do not have to propogate deletes
+ Set<FileRef> droppedFiles = new HashSet<FileRef>();
+ droppedFiles.addAll(inputFiles);
+ if (plan != null)
+ droppedFiles.addAll(plan.deleteFiles);
+ propogateDeletes = !(droppedFiles.equals(allFiles.keySet()));
+ log.debug("Major compaction plan: " + plan + " propogate deletes : " + propogateDeletes);
+ filesToCompact = new HashMap<FileRef,DataFileValue>(allFiles);
+ filesToCompact.keySet().retainAll(inputFiles);
+
+ t3 = System.currentTimeMillis();
+
+ getDatafileManager().reserveMajorCompactingFiles(filesToCompact.keySet());
+ }
+
+ try {
+
+ log.debug(String.format("MajC initiate lock %.2f secs, wait %.2f secs", (t3 - t2) / 1000.0, (t2 - t1) / 1000.0));
+
+ Pair<Long,List<IteratorSetting>> compactionId = null;
+ if (!propogateDeletes) {
+ // compacting everything, so update the compaction id in metadata
+ try {
+ compactionId = getCompactionID();
+ } catch (NoNodeException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ List<IteratorSetting> compactionIterators = new ArrayList<IteratorSetting>();
+ if (compactionId != null) {
+ if (reason == MajorCompactionReason.USER) {
+ if (getCompactionCancelID() >= compactionId.getFirst()) {
+ // compaction was canceled
+ return majCStats;
+ }
+
+ synchronized (this) {
+ if (lastCompactID >= compactionId.getFirst())
+ // already compacted
+ return majCStats;
+ }
+ }
+
+ compactionIterators = compactionId.getSecond();
+ }
+
+ // need to handle case where only one file is being major compacted
+ while (filesToCompact.size() > 0) {
+
+ int numToCompact = maxFilesToCompact;
+
+ if (filesToCompact.size() > maxFilesToCompact && filesToCompact.size() < 2 * maxFilesToCompact) {
+ // on the second to last compaction pass, compact the minimum amount of files possible
+ numToCompact = filesToCompact.size() - maxFilesToCompact + 1;
+ }
+
+ Set<FileRef> smallestFiles = removeSmallest(filesToCompact, numToCompact);
+
+ FileRef fileName = getNextMapFilename((filesToCompact.size() == 0 && !propogateDeletes) ? "A" : "C");
+ FileRef compactTmpName = new FileRef(fileName.path().toString() + "_tmp");
+
+ AccumuloConfiguration tableConf = createTableConfiguration(tableConfiguration, plan);
+
+ Span span = Trace.start("compactFiles");
+ try {
+
+ CompactionEnv cenv = new CompactionEnv() {
+ @Override
+ public boolean isCompactionEnabled() {
+ return Tablet.this.isCompactionEnabled();
+ }
+
+ @Override
+ public IteratorScope getIteratorScope() {
+ return IteratorScope.majc;
+ }
+ };
+
+ HashMap<FileRef,DataFileValue> copy = new HashMap<FileRef,DataFileValue>(getDatafileManager().getDatafileSizes());
+ if (!copy.keySet().containsAll(smallestFiles))
+ throw new IllegalStateException("Cannot find data file values for " + smallestFiles);
+
+ copy.keySet().retainAll(smallestFiles);
+
+ log.debug("Starting MajC " + extent + " (" + reason + ") " + copy.keySet() + " --> " + compactTmpName + " " + compactionIterators);
+
+ // always propagate deletes, unless last batch
+ boolean lastBatch = filesToCompact.isEmpty();
+ Compactor compactor = new Compactor(this, copy, null, compactTmpName, lastBatch ? propogateDeletes : true, cenv, compactionIterators,
+ reason.ordinal(), tableConf);
+
+ CompactionStats mcs = compactor.call();
+
+ span.data("files", "" + smallestFiles.size());
+ span.data("read", "" + mcs.getEntriesRead());
+ span.data("written", "" + mcs.getEntriesWritten());
+ majCStats.add(mcs);
+
+ if (lastBatch && plan != null && plan.deleteFiles != null) {
+ smallestFiles.addAll(plan.deleteFiles);
+ }
+ getDatafileManager().bringMajorCompactionOnline(smallestFiles, compactTmpName, fileName,
+ filesToCompact.size() == 0 && compactionId != null ? compactionId.getFirst() : null,
+ new DataFileValue(mcs.getFileSize(), mcs.getEntriesWritten()));
+
+ // when major compaction produces a file w/ zero entries, it will be deleted... do not want
+ // to add the deleted file
+ if (filesToCompact.size() > 0 && mcs.getEntriesWritten() > 0) {
+ filesToCompact.put(fileName, new DataFileValue(mcs.getFileSize(), mcs.getEntriesWritten()));
+ }
+ } finally {
+ span.stop();
+ }
+
+ }
+ return majCStats;
+ } finally {
+ synchronized (Tablet.this) {
+ getDatafileManager().clearMajorCompactingFile();
+ }
+ }
+ }
+
+ protected AccumuloConfiguration createTableConfiguration(TableConfiguration base, CompactionPlan plan) {
+ if (plan == null || plan.writeParameters == null)
+ return base;
+ WriteParameters p = plan.writeParameters;
+ ConfigurationCopy result = new ConfigurationCopy(base);
+ if (p.getHdfsBlockSize() > 0)
+ result.set(Property.TABLE_FILE_BLOCK_SIZE, "" + p.getHdfsBlockSize());
+ if (p.getBlockSize() > 0)
+ result.set(Property.TABLE_FILE_COMPRESSED_BLOCK_SIZE, "" + p.getBlockSize());
+ if (p.getIndexBlockSize() > 0)
+ result.set(Property.TABLE_FILE_COMPRESSED_BLOCK_SIZE_INDEX, "" + p.getIndexBlockSize());
+ if (p.getCompressType() != null)
+ result.set(Property.TABLE_FILE_COMPRESSION_TYPE, p.getCompressType());
+ if (p.getReplication() != 0)
+ result.set(Property.TABLE_FILE_REPLICATION, "" + p.getReplication());
+ return result;
+ }
+
+ private Set<FileRef> removeSmallest(Map<FileRef,DataFileValue> filesToCompact, int maxFilesToCompact) {
+ // ensure this method works properly when multiple files have the same size
+
+ PriorityQueue<Pair<FileRef,Long>> fileHeap = new PriorityQueue<Pair<FileRef,Long>>(filesToCompact.size(), new Comparator<Pair<FileRef,Long>>() {
+ @Override
+ public int compare(Pair<FileRef,Long> o1, Pair<FileRef,Long> o2) {
+ if (o1.getSecond() == o2.getSecond())
+ return o1.getFirst().compareTo(o2.getFirst());
+ if (o1.getSecond() < o2.getSecond())
+ return -1;
+ return 1;
+ }
+ });
+
+ for (Iterator<Entry<FileRef,DataFileValue>> iterator = filesToCompact.entrySet().iterator(); iterator.hasNext();) {
+ Entry<FileRef,DataFileValue> entry = iterator.next();
+ fileHeap.add(new Pair<FileRef,Long>(entry.getKey(), entry.getValue().getSize()));
+ }
+
+ Set<FileRef> smallestFiles = new HashSet<FileRef>();
+ while (smallestFiles.size() < maxFilesToCompact && fileHeap.size() > 0) {
+ Pair<FileRef,Long> pair = fileHeap.remove();
+ filesToCompact.remove(pair.getFirst());
+ smallestFiles.add(pair.getFirst());
+ }
+
+ return smallestFiles;
+ }
+
+ // END PRIVATE METHODS RELATED TO MAJOR COMPACTION
+
+ /**
+ * Performs a major compaction on the tablet. If needsSplit() returns true, the tablet is split and a reference to the new tablet is returned.
+ */
+
+ CompactionStats majorCompact(MajorCompactionReason reason, long queued) {
+
+ CompactionStats majCStats = null;
+ boolean success = false;
+ long start = System.currentTimeMillis();
+
+ // Always trace majC
+ Span span = Trace.on("majorCompaction");
+
+ try {
+ timer.incrementStatusMajor();
+
+ synchronized (this) {
+ // check that compaction is still needed - defer to splitting
+ majorCompactionQueued.remove(reason);
+
+ if (isClosing() || isClosed() || !needsMajorCompaction(reason) || isMajorCompactionRunning() || needsSplit()) {
+ return null;
+ }
+
+ majorCompactionState = CompactionState.WAITING_TO_START;
+ }
+
+ try {
+ majCStats = _majorCompact(reason);
+ if (reason == MajorCompactionReason.CHOP) {
+ MetadataTableUtil.chopped(getExtent(), this.getTabletServer().getLock());
+ getTabletServer().enqueueMasterMessage(new TabletStatusMessage(TabletLoadState.CHOPPED, extent));
+ }
+ success = true;
+ } catch (CompactionCanceledException mcce) {
+ log.debug("Major compaction canceled, extent = " + getExtent());
+ } catch (Throwable t) {
+ log.error("MajC Failed, extent = " + getExtent());
+ log.error("MajC Failed, message = " + (t.getMessage() == null ? t.getClass().getName() : t.getMessage()), t);
+ } finally {
+ // ensure we always reset boolean, even
+ // when an exception is thrown
+ synchronized (this) {
+ majorCompactionState = null;
+ this.notifyAll();
+ }
+
+ Span curr = Trace.currentTrace();
+ curr.data("extent", "" + getExtent());
+ if (majCStats != null) {
+ curr.data("read", "" + majCStats.getEntriesRead());
+ curr.data("written", "" + majCStats.getEntriesWritten());
+ }
+ }
+ } finally {
+ span.stop();
+ long count = 0;
+ if (majCStats != null)
+ count = majCStats.getEntriesRead();
+ timer.updateTime(Operation.MAJOR, queued, start, count, !success);
+ }
+
+ return majCStats;
+ }
+
+ /**
+ * Returns a KeyExtent object representing this tablet's key range.
+ *
+ * @return extent
+ */
+ @Override
+ public KeyExtent getExtent() {
+ return extent;
+ }
+
+ synchronized void computeNumEntries() {
+ Collection<DataFileValue> vals = getDatafileManager().getDatafileSizes().values();
+
+ long numEntries = 0;
+
+ for (DataFileValue tableValue : vals) {
+ numEntries += tableValue.getNumEntries();
+ }
+
+ this.numEntriesInMemory = getTabletMemory().getNumEntries();
+ numEntries += getTabletMemory().getNumEntries();
+
+ this.numEntries = numEntries;
+ }
+
+ public long getNumEntries() {
+ return numEntries;
+ }
+
+ public long getNumEntriesInMemory() {
+ return numEntriesInMemory;
+ }
+
+ public synchronized boolean isClosing() {
+ return closeState == CloseState.CLOSING;
+ }
+
+ public synchronized boolean isClosed() {
+ return closeState == CloseState.CLOSED || closeState == CloseState.COMPLETE;
+ }
+
+ public synchronized boolean isCloseComplete() {
+ return closeState == CloseState.COMPLETE;
+ }
+
+ public boolean isMajorCompactionRunning() {
+ return majorCompactionState != null;
+ }
+
+ public boolean isMinorCompactionQueued() {
+ return minorCompactionState == CompactionState.WAITING_TO_START;
+ }
+
+ public boolean isMinorCompactionRunning() {
+ return minorCompactionState == CompactionState.IN_PROGRESS;
+ }
+
+ public boolean isMajorCompactionQueued() {
+ return majorCompactionQueued.size() > 0;
+ }
+
+ public TreeMap<KeyExtent,SplitInfo> split(byte[] sp) throws IOException {
+
+ if (sp != null && extent.getEndRow() != null && extent.getEndRow().equals(new Text(sp))) {
+ throw new IllegalArgumentException();
+ }
+
+ if (sp != null && sp.length > tableConfiguration.getMemoryInBytes(Property.TABLE_MAX_END_ROW_SIZE)) {
+ String msg = "Cannot split tablet " + extent + ", selected split point too long. Length : " + sp.length;
+ log.warn(msg);
+ throw new IOException(msg);
+ }
+
+ if (extent.isRootTablet()) {
+ String msg = "Cannot split root tablet";
+ log.warn(msg);
+ throw new RuntimeException(msg);
+ }
+
+ try {
+ initiateClose(true, false, false);
+ } catch (IllegalStateException ise) {
+ log.debug("File " + extent + " not splitting : " + ise.getMessage());
+ return null;
+ }
+
+ // obtain this info outside of synch block since it will involve opening
+ // the map files... it is ok if the set of map files changes, because
+ // this info is used for optimization... it is ok if map files are missing
+ // from the set... can still query and insert into the tablet while this
+ // map file operation is happening
+ Map<FileRef,FileUtil.FileInfo> firstAndLastRows = FileUtil.tryToGetFirstAndLastRows(getTabletServer().getFileSystem(),
+ getTabletServer().getConfiguration(), getDatafileManager().getFiles());
+
+ synchronized (this) {
+ // java needs tuples ...
+ TreeMap<KeyExtent,SplitInfo> newTablets = new TreeMap<KeyExtent,SplitInfo>();
+
+ long t1 = System.currentTimeMillis();
+ // choose a split point
+ SplitRowSpec splitPoint;
+ if (sp == null)
+ splitPoint = findSplitRow(getDatafileManager().getFiles());
+ else {
+ Text tsp = new Text(sp);
+ splitPoint = new SplitRowSpec(FileUtil.estimatePercentageLTE(getTabletServer().getFileSystem(), getTabletServer().getConfiguration(),
+ extent.getPrevEndRow(), extent.getEndRow(), FileUtil.toPathStrings(getDatafileManager().getFiles()), tsp), tsp);
+ }
+
+ if (splitPoint == null || splitPoint.row == null) {
+ log.info("had to abort split because splitRow was null");
+ closeState = CloseState.OPEN;
+ return null;
+ }
+
+ closeState = CloseState.CLOSING;
+ completeClose(true, false);
+
+ Text midRow = splitPoint.row;
+ double splitRatio = splitPoint.splitRatio;
+
+ KeyExtent low = new KeyExtent(extent.getTableId(), midRow, extent.getPrevEndRow());
+ KeyExtent high = new KeyExtent(extent.getTableId(), extent.getEndRow(), midRow);
+
+ String lowDirectory = TabletOperations.createTabletDirectory(getTabletServer().getFileSystem(), extent.getTableId().toString(), midRow);
+
+ // write new tablet information to MetadataTable
+ SortedMap<FileRef,DataFileValue> lowDatafileSizes = new TreeMap<FileRef,DataFileValue>();
+ SortedMap<FileRef,DataFileValue> highDatafileSizes = new TreeMap<FileRef,DataFileValue>();
+ List<FileRef> highDatafilesToRemove = new ArrayList<FileRef>();
+
+ MetadataTableUtil.splitDatafiles(extent.getTableId(), midRow, splitRatio, firstAndLastRows, getDatafileManager().getDatafileSizes(), lowDatafileSizes,
+ highDatafileSizes, highDatafilesToRemove);
+
+ log.debug("Files for low split " + low + " " + lowDatafileSizes.keySet());
+ log.debug("Files for high split " + high + " " + highDatafileSizes.keySet());
+
+ String time = tabletTime.getMetadataValue();
+
+ // it is possible that some of the bulk loading flags will be deleted after being read below because the bulk load
+
<TRUNCATED>
[05/16] git commit: ACCUMULO-3242 Fix up the retry logic in ZooCache.
Posted by el...@apache.org.
ACCUMULO-3242 Fix up the retry logic in ZooCache.
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/423cf10a
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/423cf10a
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/423cf10a
Branch: refs/heads/1.6
Commit: 423cf10a32d062e70ed97d1f85bb3c5c8642acbe
Parents: 1636055
Author: Josh Elser <el...@apache.org>
Authored: Sun Oct 19 12:55:34 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:16:04 2014 -0400
----------------------------------------------------------------------
.../apache/accumulo/fate/zookeeper/ZooCache.java | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/423cf10a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooCache.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooCache.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooCache.java
index d9eb243..b3dd19a 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooCache.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooCache.java
@@ -16,7 +16,6 @@
*/
package org.apache.accumulo.fate.zookeeper;
-import com.google.common.annotations.VisibleForTesting;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -37,6 +36,8 @@ import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
+import com.google.common.annotations.VisibleForTesting;
+
/**
* A cache for values stored in ZooKeeper. Values are kept up to date as they
* change.
@@ -138,6 +139,9 @@ public class ZooCache {
}
private interface ZooRunnable {
+ /**
+ * Runs an operation against ZooKeeper, automatically retrying in the face of KeeperExceptions
+ */
void run(ZooKeeper zooKeeper) throws KeeperException, InterruptedException;
}
@@ -154,8 +158,12 @@ public class ZooCache {
return;
} catch (KeeperException e) {
- if (e.code() == Code.NONODE) {
+ final Code code = e.code();
+ if (code == Code.NONODE) {
log.error("Looked up non-existent node in cache " + e.getPath(), e);
+ } else if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ log.warn("Saw (possibly) transient exception communicating with ZooKeeper, wil retry", e);
+ continue;
}
log.warn("Zookeeper error, will retry", e);
} catch (InterruptedException e) {
@@ -168,7 +176,7 @@ public class ZooCache {
// do not hold lock while sleeping
wait(sleepTime);
} catch (InterruptedException e) {
- e.printStackTrace();
+ log.info("Interrupted waiting before retrying ZooKeeper operation", e);
}
if (sleepTime < 10000)
sleepTime = (int) (sleepTime + sleepTime * Math.random());
@@ -244,7 +252,7 @@ public class ZooCache {
/*
* The following call to exists() is important, since we are caching that a node does not exist. Once the node comes into existence, it will be added to
* the cache. But this notification of a node coming into existence will only be given if exists() was previously called.
- *
+ *
* If the call to exists() is bypassed and only getData() is called with a special case that looks for Code.NONODE in the KeeperException, then
* non-existence can not be cached.
*/
[13/16] git commit: ACCUMULO-3242 Some general code cleanup.
Unnecessary javadoc and duplicative ZooReaderWriter.getInstance() calls
Posted by el...@apache.org.
ACCUMULO-3242 Some general code cleanup. Unnecessary javadoc and duplicative ZooReaderWriter.getInstance() calls
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/0e4159c3
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/0e4159c3
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/0e4159c3
Branch: refs/heads/1.6
Commit: 0e4159c3f389b71c36f81e07dce0e541ec40b183
Parents: 423cf10
Author: Josh Elser <el...@apache.org>
Authored: Sun Oct 19 20:36:08 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:36:08 2014 -0400
----------------------------------------------------------------------
.../fate/zookeeper/IZooReaderWriter.java | 1 -
.../server/security/handler/ZKPermHandler.java | 24 +++++++++++---------
2 files changed, 13 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e4159c3/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
index 2f3ed62..5b0a304 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
@@ -65,7 +65,6 @@ public interface IZooReaderWriter extends IZooReader {
void mkdirs(String path) throws KeeperException, InterruptedException;
- @Override
void sync(String path) throws KeeperException, InterruptedException;
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e4159c3/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
index 3cac2e9..be4806b 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
@@ -45,7 +45,7 @@ import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.Code;
/**
- *
+ *
*/
public class ZKPermHandler implements PermissionHandler {
private static final Logger log = Logger.getLogger(ZKAuthorizor.class);
@@ -79,16 +79,17 @@ public class ZKPermHandler implements PermissionHandler {
@Override
public boolean hasTablePermission(String user, String table, TablePermission permission) throws TableNotFoundException {
byte[] serializedPerms;
+ final ZooReaderWriter zrw = ZooReaderWriter.getInstance();
try {
String path = ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table;
- ZooReaderWriter.getInstance().sync(path);
- serializedPerms = ZooReaderWriter.getInstance().getData(path, null);
+ zrw.sync(path);
+ serializedPerms = zrw.getData(path, null);
} catch (KeeperException e) {
if (e.code() == Code.NONODE) {
// maybe the table was just deleted?
try {
// check for existence:
- ZooReaderWriter.getInstance().getData(ZKTablePath + "/" + table, null);
+ zrw.getData(ZKTablePath + "/" + table, null);
// it's there, you don't have permission
return false;
} catch (InterruptedException ex) {
@@ -127,16 +128,17 @@ public class ZKPermHandler implements PermissionHandler {
@Override
public boolean hasNamespacePermission(String user, String namespace, NamespacePermission permission) throws NamespaceNotFoundException {
byte[] serializedPerms;
+ final ZooReaderWriter zrw = ZooReaderWriter.getInstance();
try {
String path = ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace;
- ZooReaderWriter.getInstance().sync(path);
- serializedPerms = ZooReaderWriter.getInstance().getData(path, null);
+ zrw.sync(path);
+ serializedPerms = zrw.getData(path, null);
} catch (KeeperException e) {
if (e.code() == Code.NONODE) {
// maybe the namespace was just deleted?
try {
// check for existence:
- ZooReaderWriter.getInstance().getData(ZKNamespacePath + "/" + namespace, null);
+ zrw.getData(ZKNamespacePath + "/" + namespace, null);
// it's there, you don't have permission
return false;
} catch (InterruptedException ex) {
@@ -213,8 +215,8 @@ public class ZKPermHandler implements PermissionHandler {
if (tablePerms.add(permission)) {
synchronized (zooCache) {
zooCache.clear(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
- IZooReaderWriter zoo = ZooReaderWriter.getInstance();
- zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, ZKSecurityTool.convertTablePermissions(tablePerms),
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table,
+ ZKSecurityTool.convertTablePermissions(tablePerms),
NodeExistsPolicy.OVERWRITE);
}
}
@@ -240,8 +242,8 @@ public class ZKPermHandler implements PermissionHandler {
if (namespacePerms.add(permission)) {
synchronized (zooCache) {
zooCache.clear(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace);
- IZooReaderWriter zoo = ZooReaderWriter.getInstance();
- zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace, ZKSecurityTool.convertNamespacePermissions(namespacePerms),
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace,
+ ZKSecurityTool.convertNamespacePermissions(namespacePerms),
NodeExistsPolicy.OVERWRITE);
}
}
[09/16] git commit: ACCUMULO-3242 Add some tests for Retry
Posted by el...@apache.org.
ACCUMULO-3242 Add some tests for Retry
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/1636055a
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/1636055a
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/1636055a
Branch: refs/heads/master
Commit: 1636055ac6d8d5fecae9e292be283b864d3d4341
Parents: 1ce12ae
Author: Josh Elser <el...@apache.org>
Authored: Sat Oct 18 16:18:41 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:16:04 2014 -0400
----------------------------------------------------------------------
.../apache/accumulo/fate/zookeeper/Retry.java | 27 +++-
.../accumulo/fate/zookeeper/RetryTest.java | 127 +++++++++++++++++++
2 files changed, 152 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1636055a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
index 63aa902..7bfaba6 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
@@ -24,7 +24,7 @@ import org.apache.log4j.Logger;
public class Retry {
private static final Logger log = Logger.getLogger(Retry.class);
- private final long maxRetries, maxWait, waitIncrement;
+ private long maxRetries, maxWait, waitIncrement;
private long retriesDone, currentWait;
/**
@@ -45,6 +45,26 @@ public class Retry {
this.currentWait = startWait;
}
+ // Visible for testing
+ void setMaxRetries(long maxRetries) {
+ this.maxRetries = maxRetries;
+ }
+
+ // Visible for testing
+ void setStartWait(long startWait) {
+ this.currentWait = startWait;
+ }
+
+ // Visible for testing
+ void setWaitIncrement(long waitIncrement) {
+ this.waitIncrement = waitIncrement;
+ }
+
+ // Visible for testing
+ void setMaxWait(long maxWait) {
+ this.maxWait = maxWait;
+ }
+
public boolean canRetry() {
return retriesDone < maxRetries;
}
@@ -67,8 +87,11 @@ public class Retry {
public void waitForNextAttempt() throws InterruptedException {
log.debug("Sleeping for " + currentWait + "ms before retrying operation");
- Thread.sleep(currentWait);
+ sleep(currentWait);
currentWait = Math.min(maxWait, currentWait + waitIncrement);
}
+ protected void sleep(long wait) throws InterruptedException {
+ Thread.sleep(wait);
+ }
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1636055a/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryTest.java
----------------------------------------------------------------------
diff --git a/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryTest.java b/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryTest.java
new file mode 100644
index 0000000..e37af01
--- /dev/null
+++ b/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.accumulo.fate.zookeeper;
+
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class RetryTest {
+
+ private Retry retry;
+ long initialWait = 1000l, waitIncrement = 1000l, maxRetries = 5;
+
+ @Before
+ public void setup() {
+ retry = new Retry(maxRetries, initialWait, waitIncrement, maxRetries * 1000l);
+ }
+
+ @Test
+ public void canRetryDoesntAlterState() {
+ for (int i = 0; i < maxRetries + 1; i++) {
+ Assert.assertTrue(retry.canRetry());
+ }
+ }
+
+ @Test
+ public void hasRetriedAfterUse() {
+ Assert.assertFalse(retry.hasRetried());
+ retry.useRetry();
+ Assert.assertTrue(retry.hasRetried());
+ }
+
+ @Test
+ public void retriesAreCompleted() {
+ for (int i = 0; i < maxRetries; i++) {
+ Assert.assertEquals(i, retry.retriesCompleted());
+ // canRetry doesn't alter retry's state
+ retry.canRetry();
+ Assert.assertEquals(i, retry.retriesCompleted());
+ // Using the retry will increase the internal count
+ retry.useRetry();
+ Assert.assertEquals(i + 1, retry.retriesCompleted());
+ }
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void usingNonExistentRetryFails() {
+ for (int i = 0; i < maxRetries; i++) {
+ Assert.assertTrue(retry.canRetry());
+ retry.useRetry();
+ }
+ Assert.assertFalse(retry.canRetry());
+ // Calling useRetry when canRetry returns false throws an exception
+ retry.useRetry();
+ }
+
+ @Test
+ public void testWaitIncrement() throws InterruptedException {
+ retry = EasyMock.createMockBuilder(Retry.class).addMockedMethod("sleep").createStrictMock();
+ retry.setMaxRetries(maxRetries);
+ retry.setStartWait(initialWait);
+ retry.setWaitIncrement(waitIncrement);
+ retry.setMaxWait(maxRetries * 1000l);
+
+ long currentWait = initialWait;
+ for (int i = 1; i <= maxRetries; i++) {
+ retry.sleep(currentWait);
+ EasyMock.expectLastCall();
+ currentWait += waitIncrement;
+ }
+
+ EasyMock.replay(retry);
+
+ while (retry.canRetry()) {
+ retry.useRetry();
+ retry.waitForNextAttempt();
+ }
+
+ EasyMock.verify(retry);
+ }
+
+ @Test
+ public void testBoundedWaitIncrement() throws InterruptedException {
+ retry = EasyMock.createMockBuilder(Retry.class).addMockedMethod("sleep").createStrictMock();
+ retry.setMaxRetries(maxRetries);
+ retry.setStartWait(initialWait);
+ retry.setWaitIncrement(waitIncrement);
+ // Make the last retry not increment in length
+ retry.setMaxWait((maxRetries - 1) * 1000l);
+
+ long currentWait = initialWait;
+ for (int i = 1; i <= maxRetries; i++) {
+ retry.sleep(currentWait);
+ EasyMock.expectLastCall();
+ if (i < maxRetries - 1) {
+ currentWait += waitIncrement;
+ }
+ }
+
+ EasyMock.replay(retry);
+
+ while (retry.canRetry()) {
+ retry.useRetry();
+ retry.waitForNextAttempt();
+ }
+
+ EasyMock.verify(retry);
+ }
+}
[14/16] git commit: ACCUMULO-3242 Some general code cleanup.
Unnecessary javadoc and duplicative ZooReaderWriter.getInstance() calls
Posted by el...@apache.org.
ACCUMULO-3242 Some general code cleanup. Unnecessary javadoc and duplicative ZooReaderWriter.getInstance() calls
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/0e4159c3
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/0e4159c3
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/0e4159c3
Branch: refs/heads/master
Commit: 0e4159c3f389b71c36f81e07dce0e541ec40b183
Parents: 423cf10
Author: Josh Elser <el...@apache.org>
Authored: Sun Oct 19 20:36:08 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:36:08 2014 -0400
----------------------------------------------------------------------
.../fate/zookeeper/IZooReaderWriter.java | 1 -
.../server/security/handler/ZKPermHandler.java | 24 +++++++++++---------
2 files changed, 13 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e4159c3/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
index 2f3ed62..5b0a304 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
@@ -65,7 +65,6 @@ public interface IZooReaderWriter extends IZooReader {
void mkdirs(String path) throws KeeperException, InterruptedException;
- @Override
void sync(String path) throws KeeperException, InterruptedException;
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/0e4159c3/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
index 3cac2e9..be4806b 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
@@ -45,7 +45,7 @@ import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.Code;
/**
- *
+ *
*/
public class ZKPermHandler implements PermissionHandler {
private static final Logger log = Logger.getLogger(ZKAuthorizor.class);
@@ -79,16 +79,17 @@ public class ZKPermHandler implements PermissionHandler {
@Override
public boolean hasTablePermission(String user, String table, TablePermission permission) throws TableNotFoundException {
byte[] serializedPerms;
+ final ZooReaderWriter zrw = ZooReaderWriter.getInstance();
try {
String path = ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table;
- ZooReaderWriter.getInstance().sync(path);
- serializedPerms = ZooReaderWriter.getInstance().getData(path, null);
+ zrw.sync(path);
+ serializedPerms = zrw.getData(path, null);
} catch (KeeperException e) {
if (e.code() == Code.NONODE) {
// maybe the table was just deleted?
try {
// check for existence:
- ZooReaderWriter.getInstance().getData(ZKTablePath + "/" + table, null);
+ zrw.getData(ZKTablePath + "/" + table, null);
// it's there, you don't have permission
return false;
} catch (InterruptedException ex) {
@@ -127,16 +128,17 @@ public class ZKPermHandler implements PermissionHandler {
@Override
public boolean hasNamespacePermission(String user, String namespace, NamespacePermission permission) throws NamespaceNotFoundException {
byte[] serializedPerms;
+ final ZooReaderWriter zrw = ZooReaderWriter.getInstance();
try {
String path = ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace;
- ZooReaderWriter.getInstance().sync(path);
- serializedPerms = ZooReaderWriter.getInstance().getData(path, null);
+ zrw.sync(path);
+ serializedPerms = zrw.getData(path, null);
} catch (KeeperException e) {
if (e.code() == Code.NONODE) {
// maybe the namespace was just deleted?
try {
// check for existence:
- ZooReaderWriter.getInstance().getData(ZKNamespacePath + "/" + namespace, null);
+ zrw.getData(ZKNamespacePath + "/" + namespace, null);
// it's there, you don't have permission
return false;
} catch (InterruptedException ex) {
@@ -213,8 +215,8 @@ public class ZKPermHandler implements PermissionHandler {
if (tablePerms.add(permission)) {
synchronized (zooCache) {
zooCache.clear(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
- IZooReaderWriter zoo = ZooReaderWriter.getInstance();
- zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, ZKSecurityTool.convertTablePermissions(tablePerms),
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table,
+ ZKSecurityTool.convertTablePermissions(tablePerms),
NodeExistsPolicy.OVERWRITE);
}
}
@@ -240,8 +242,8 @@ public class ZKPermHandler implements PermissionHandler {
if (namespacePerms.add(permission)) {
synchronized (zooCache) {
zooCache.clear(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace);
- IZooReaderWriter zoo = ZooReaderWriter.getInstance();
- zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace, ZKSecurityTool.convertNamespacePermissions(namespacePerms),
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace,
+ ZKSecurityTool.convertNamespacePermissions(namespacePerms),
NodeExistsPolicy.OVERWRITE);
}
}
[08/16] git commit: ACCUMULO-3242 Rip out the rest of the improper ZK
usages in ZooUtil.
Posted by el...@apache.org.
ACCUMULO-3242 Rip out the rest of the improper ZK usages in ZooUtil.
The way ZooUtil was written made it really hard to correctly handle
session expirations. Remove ZooKeeper as an argument and use ZooSession
(like ZooReader and ZooReaderWriter) which should correctly account
for a new connection.
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/1ce12aea
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/1ce12aea
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/1ce12aea
Branch: refs/heads/master
Commit: 1ce12aea2c61ad804e8c27a9a9d1b125bf9d2752
Parents: 6e71636
Author: Josh Elser <el...@apache.org>
Authored: Sat Oct 18 15:46:56 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:16:04 2014 -0400
----------------------------------------------------------------------
.../fate/zookeeper/IZooReaderWriter.java | 35 ++---
.../apache/accumulo/fate/zookeeper/Retry.java | 4 +-
.../accumulo/fate/zookeeper/RetryFactory.java | 6 +-
.../accumulo/fate/zookeeper/ZooReader.java | 2 +-
.../fate/zookeeper/ZooReaderWriter.java | 29 ++--
.../apache/accumulo/fate/zookeeper/ZooUtil.java | 143 +++++++++++--------
.../apache/accumulo/server/init/Initialize.java | 10 +-
7 files changed, 137 insertions(+), 92 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
index afc2250..2f3ed62 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReaderWriter.java
@@ -25,44 +25,47 @@ import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
public interface IZooReaderWriter extends IZooReader {
-
+
ZooKeeper getZooKeeper();
-
+
void recursiveDelete(String zPath, NodeMissingPolicy policy) throws KeeperException, InterruptedException;
-
+
void recursiveDelete(String zPath, int version, NodeMissingPolicy policy) throws KeeperException, InterruptedException;
-
+
/**
* Create a persistent node with the default ACL
- *
+ *
* @return true if the node was created or altered; false if it was skipped
*/
boolean putPersistentData(String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException;
-
+
boolean putPrivatePersistentData(String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException;
-
+
void putPersistentData(String zPath, byte[] data, int version, NodeExistsPolicy policy) throws KeeperException, InterruptedException;
+ boolean putPersistentData(String zPath, byte[] data, int version, NodeExistsPolicy policy, List<ACL> acls) throws KeeperException, InterruptedException;
+
String putPersistentSequential(String zPath, byte[] data) throws KeeperException, InterruptedException;
-
+
String putEphemeralSequential(String zPath, byte[] data) throws KeeperException, InterruptedException;
-
+
String putEphemeralData(String zPath, byte[] data) throws KeeperException, InterruptedException;
void recursiveCopyPersistent(String source, String destination, NodeExistsPolicy policy) throws KeeperException, InterruptedException;
-
+
void delete(String path, int version) throws InterruptedException, KeeperException;
-
+
interface Mutator {
byte[] mutate(byte[] currentValue) throws Exception;
}
-
+
byte[] mutate(String zPath, byte[] createValue, List<ACL> acl, Mutator mutator) throws Exception;
-
+
boolean isLockHeld(ZooUtil.LockID lockID) throws KeeperException, InterruptedException;
-
+
void mkdirs(String path) throws KeeperException, InterruptedException;
-
+
+ @Override
void sync(String path) throws KeeperException, InterruptedException;
-
+
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
index 4a37172..63aa902 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
@@ -19,7 +19,7 @@ package org.apache.accumulo.fate.zookeeper;
import org.apache.log4j.Logger;
/**
- *
+ * Encapsulates the retrying implementation for some operation. Provides bounded retry attempts with a bounded, linear backoff.
*/
public class Retry {
private static final Logger log = Logger.getLogger(Retry.class);
@@ -37,7 +37,7 @@ public class Retry {
* @param waitIncrement
* The amount of time (ms) to increment next wait time by
*/
- public Retry(long maxRetries, long startWait, long maxWait, long waitIncrement) {
+ public Retry(long maxRetries, long startWait, long waitIncrement, long maxWait) {
this.maxRetries = maxRetries;
this.maxWait = maxWait;
this.waitIncrement = waitIncrement;
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
index 3fcb738..ff96350 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
@@ -17,13 +17,15 @@
package org.apache.accumulo.fate.zookeeper;
/**
- *
+ * Creates {@link Retry} instances with the given parameters
*/
public class RetryFactory {
+ public static final long DEFAULT_MAX_RETRIES = 10l, DEFAULT_START_WAIT = 250l, DEFAULT_WAIT_INCREMENT = 250l, DEFAULT_MAX_WAIT = 5000l;
+ public static final RetryFactory DEFAULT_INSTANCE = new RetryFactory(DEFAULT_MAX_RETRIES, DEFAULT_START_WAIT, DEFAULT_WAIT_INCREMENT, DEFAULT_MAX_WAIT);
private final long maxRetries, startWait, maxWait, waitIncrement;
- public RetryFactory(long maxRetries, long startWait, long maxWait, long waitIncrement) {
+ public RetryFactory(long maxRetries, long startWait, long waitIncrement, long maxWait) {
this.maxRetries = maxRetries;
this.startWait = startWait;
this.maxWait = maxWait;
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
index fd7938a..5706cf3 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
@@ -223,6 +223,6 @@ public class ZooReader implements IZooReader {
public ZooReader(String keepers, int timeout) {
this.keepers = keepers;
this.timeout = timeout;
- this.retryFactory = new RetryFactory(10l, 250l, 250l, 5000l);
+ this.retryFactory = RetryFactory.DEFAULT_INSTANCE;
}
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
index 79c2219..5b6447c 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
@@ -22,6 +22,7 @@ import java.util.List;
import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeMissingPolicy;
+import org.apache.accumulo.fate.zookeeper.ZooUtil.ZooKeeperConnectionInfo;
import org.apache.log4j.Logger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
@@ -38,6 +39,7 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
private static ZooReaderWriter instance = null;
private final String scheme;
private final byte[] auth;
+ private final ZooKeeperConnectionInfo info;
@Override
public ZooKeeper getZooKeeper() {
@@ -52,16 +54,17 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
super(string, timeInMillis);
this.scheme = scheme;
this.auth = Arrays.copyOf(auth, auth.length);
+ this.info = new ZooKeeperConnectionInfo(string, timeInMillis, scheme, this.auth);
}
@Override
public void recursiveDelete(String zPath, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
- ZooUtil.recursiveDelete(getZooKeeper(), zPath, policy);
+ ZooUtil.recursiveDelete(info, zPath, policy);
}
@Override
public void recursiveDelete(String zPath, int version, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
- ZooUtil.recursiveDelete(getZooKeeper(), zPath, version, policy);
+ ZooUtil.recursiveDelete(info, zPath, version, policy);
}
/**
@@ -71,37 +74,43 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
*/
@Override
public boolean putPersistentData(String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
- return ZooUtil.putPersistentData(getZooKeeper(), zPath, data, policy);
+ return ZooUtil.putPersistentData(info, zPath, data, policy);
+ }
+
+ @Override
+ public boolean putPersistentData(String zPath, byte[] data, int version, NodeExistsPolicy policy, List<ACL> acls) throws KeeperException,
+ InterruptedException {
+ return ZooUtil.putPersistentData(info, zPath, data, version, policy, acls);
}
@Override
public boolean putPrivatePersistentData(String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
- return ZooUtil.putPrivatePersistentData(getZooKeeper(), zPath, data, policy);
+ return ZooUtil.putPrivatePersistentData(info, zPath, data, policy);
}
@Override
public void putPersistentData(String zPath, byte[] data, int version, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
- ZooUtil.putPersistentData(getZooKeeper(), zPath, data, version, policy);
+ ZooUtil.putPersistentData(info, zPath, data, version, policy);
}
@Override
public String putPersistentSequential(String zPath, byte[] data) throws KeeperException, InterruptedException {
- return ZooUtil.putPersistentSequential(getZooKeeper(), zPath, data);
+ return ZooUtil.putPersistentSequential(info, zPath, data);
}
@Override
public String putEphemeralData(String zPath, byte[] data) throws KeeperException, InterruptedException {
- return ZooUtil.putEphemeralData(getZooKeeper(), zPath, data);
+ return ZooUtil.putEphemeralData(info, zPath, data);
}
@Override
public String putEphemeralSequential(String zPath, byte[] data) throws KeeperException, InterruptedException {
- return ZooUtil.putEphemeralSequential(getZooKeeper(), zPath, data);
+ return ZooUtil.putEphemeralSequential(info, zPath, data);
}
@Override
public void recursiveCopyPersistent(String source, String destination, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
- ZooUtil.recursiveCopyPersistent(getZooKeeper(), source, destination, policy);
+ ZooUtil.recursiveCopyPersistent(info, source, destination, policy);
}
@Override
@@ -189,7 +198,7 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
@Override
public boolean isLockHeld(ZooUtil.LockID lockID) throws KeeperException, InterruptedException {
- return ZooUtil.isLockHeld(getZooKeeper(), lockID);
+ return ZooUtil.isLockHeld(info, lockID);
}
@Override
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
index e0d8831..674c1d8 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
@@ -81,6 +81,19 @@ public class ZooUtil {
}
}
+ protected static class ZooKeeperConnectionInfo {
+ String keepers, scheme;
+ int timeout;
+ byte[] auth;
+
+ public ZooKeeperConnectionInfo(String keepers, int timeout, String scheme, byte[] auth) {
+ this.keepers = keepers;
+ this.timeout = timeout;
+ this.scheme = scheme;
+ this.auth = auth;
+ }
+ }
+
public static final List<ACL> PRIVATE;
public static final List<ACL> PUBLIC;
private static final RetryFactory RETRY_FACTORY;
@@ -90,7 +103,15 @@ public class ZooUtil {
PUBLIC = new ArrayList<ACL>();
PUBLIC.addAll(PRIVATE);
PUBLIC.add(new ACL(Perms.READ, Ids.ANYONE_ID_UNSAFE));
- RETRY_FACTORY = new RetryFactory(10l, 250l, 250l, 5000l);
+ RETRY_FACTORY = RetryFactory.DEFAULT_INSTANCE;
+ }
+
+ protected static ZooKeeper getZooKeeper(ZooKeeperConnectionInfo info) {
+ return getZooKeeper(info.keepers, info.timeout, info.scheme, info.auth);
+ }
+
+ protected static ZooKeeper getZooKeeper(String keepers, int timeout, String scheme, byte[] auth) {
+ return ZooSession.getSession(keepers, timeout, scheme, auth);
}
protected static void retryOrThrow(Retry retry, KeeperException e) throws KeeperException {
@@ -110,7 +131,7 @@ public class ZooUtil {
* @param zPath
* the path to delete
*/
- public static void recursiveDelete(ZooKeeper zk, String zPath, int version, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
+ static void recursiveDelete(ZooKeeperConnectionInfo info, String zPath, int version, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
if (policy.equals(NodeMissingPolicy.CREATE))
throw new IllegalArgumentException(policy.name() + " is invalid for this operation");
try {
@@ -118,12 +139,11 @@ public class ZooUtil {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- children = zk.getChildren(zPath, false);
+ children = getZooKeeper(info).getChildren(zPath, false);
break;
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -132,17 +152,17 @@ public class ZooUtil {
retry.waitForNextAttempt();
}
for (String child : children)
- recursiveDelete(zk, zPath + "/" + child, NodeMissingPolicy.SKIP);
+ recursiveDelete(info, zPath + "/" + child, NodeMissingPolicy.SKIP);
Stat stat;
while (true) {
try {
- stat = zk.exists(zPath, null);
+ stat = getZooKeeper(info).exists(zPath, null);
// Node exists
if (stat != null) {
try {
// Try to delete it
- zk.delete(zPath, stat.getVersion());
+ getZooKeeper(info).delete(zPath, stat.getVersion());
return;
} catch (NoNodeException e) {
// If the node is gone now, it's ok if we have SKIP
@@ -156,7 +176,6 @@ public class ZooUtil {
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -172,8 +191,8 @@ public class ZooUtil {
}
}
- public static void recursiveDelete(ZooKeeper zk, String zPath, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
- recursiveDelete(zk, zPath, -1, policy);
+ public static void recursiveDelete(ZooKeeperConnectionInfo info, String zPath, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
+ recursiveDelete(info, zPath, -1, policy);
}
/**
@@ -181,21 +200,24 @@ public class ZooUtil {
*
* @return true if the node was created or altered; false if it was skipped
*/
- public static boolean putPersistentData(ZooKeeper zk, String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
- return putData(zk, zPath, data, CreateMode.PERSISTENT, -1, policy, PUBLIC);
+ public static boolean putPersistentData(ZooKeeperConnectionInfo info, String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException,
+ InterruptedException {
+ return putData(info, zPath, data, CreateMode.PERSISTENT, -1, policy, PUBLIC);
}
- public static boolean putPersistentData(ZooKeeper zk, String zPath, byte[] data, int version, NodeExistsPolicy policy) throws KeeperException,
+ public static boolean putPersistentData(ZooKeeperConnectionInfo info, String zPath, byte[] data, int version, NodeExistsPolicy policy)
+ throws KeeperException,
InterruptedException {
- return putData(zk, zPath, data, CreateMode.PERSISTENT, version, policy, PUBLIC);
+ return putData(info, zPath, data, CreateMode.PERSISTENT, version, policy, PUBLIC);
}
- public static boolean putPersistentData(ZooKeeper zk, String zPath, byte[] data, int version, NodeExistsPolicy policy, List<ACL> acls)
+ public static boolean putPersistentData(ZooKeeperConnectionInfo info, String zPath, byte[] data, int version, NodeExistsPolicy policy, List<ACL> acls)
throws KeeperException, InterruptedException {
- return putData(zk, zPath, data, CreateMode.PERSISTENT, version, policy, acls);
+ return putData(info, zPath, data, CreateMode.PERSISTENT, version, policy, acls);
}
- private static boolean putData(ZooKeeper zk, String zPath, byte[] data, CreateMode mode, int version, NodeExistsPolicy policy, List<ACL> acls)
+ private static boolean putData(ZooKeeperConnectionInfo info, String zPath, byte[] data, CreateMode mode, int version,
+ NodeExistsPolicy policy, List<ACL> acls)
throws KeeperException, InterruptedException {
if (policy == null)
policy = NodeExistsPolicy.FAIL;
@@ -203,7 +225,7 @@ public class ZooUtil {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- zk.create(zPath, data, acls, mode);
+ getZooKeeper(info).create(zPath, data, acls, mode);
return true;
} catch (KeeperException e) {
final Code code = e.code();
@@ -214,26 +236,24 @@ public class ZooUtil {
case OVERWRITE:
// overwrite the data in the node when it already exists
try {
- zk.setData(zPath, data, version);
+ getZooKeeper(info).setData(zPath, data, version);
return true;
} catch (KeeperException e2) {
final Code code2 = e2.code();
if (code2 == Code.NONODE) {
// node delete between create call and set data, so try create call again
continue;
- } else if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
- retryOrThrow(retry, e);
+ } else if (code2 == Code.CONNECTIONLOSS || code2 == Code.OPERATIONTIMEOUT || code2 == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e2);
} else {
// unhandled exception on setData()
- throw e;
+ throw e2;
}
}
default:
throw e;
}
} else if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
// unhandled exception on create()
@@ -246,15 +266,14 @@ public class ZooUtil {
}
}
- public static byte[] getData(ZooKeeper zk, String zPath, Stat stat) throws KeeperException, InterruptedException {
+ public static byte[] getData(ZooKeeperConnectionInfo info, String zPath, Stat stat) throws KeeperException, InterruptedException {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- return zk.getData(zPath, false, stat);
+ return getZooKeeper(info).getData(zPath, false, stat);
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -265,15 +284,14 @@ public class ZooUtil {
}
}
- public static Stat getStatus(ZooKeeper zk, String zPath) throws KeeperException, InterruptedException {
+ public static Stat getStatus(ZooKeeperConnectionInfo info, String zPath) throws KeeperException, InterruptedException {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- return zk.exists(zPath, false);
+ return getZooKeeper(info).exists(zPath, false);
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -284,16 +302,16 @@ public class ZooUtil {
}
}
- public static boolean exists(ZooKeeper zk, String zPath) throws KeeperException, InterruptedException {
- return getStatus(zk, zPath) != null;
+ public static boolean exists(ZooKeeperConnectionInfo info, String zPath) throws KeeperException, InterruptedException {
+ return getStatus(info, zPath) != null;
}
- public static void recursiveCopyPersistent(ZooKeeper zk, String source, String destination, NodeExistsPolicy policy) throws KeeperException,
+ public static void recursiveCopyPersistent(ZooKeeperConnectionInfo info, String source, String destination, NodeExistsPolicy policy) throws KeeperException,
InterruptedException {
Stat stat = null;
- if (!exists(zk, source))
+ if (!exists(info, source))
throw KeeperException.create(Code.NONODE, source);
- if (exists(zk, destination)) {
+ if (exists(info, destination)) {
switch (policy) {
case OVERWRITE:
break;
@@ -306,31 +324,48 @@ public class ZooUtil {
}
stat = new Stat();
- byte[] data = getData(zk, source, stat);
+ byte[] data = getData(info, source, stat);
if (stat.getEphemeralOwner() == 0) {
if (data == null)
throw KeeperException.create(Code.NONODE, source);
- putPersistentData(zk, destination, data, policy);
- if (stat.getNumChildren() > 0)
- for (String child : zk.getChildren(source, false))
- recursiveCopyPersistent(zk, source + "/" + child, destination + "/" + child, policy);
+ putPersistentData(info, destination, data, policy);
+ if (stat.getNumChildren() > 0) {
+ List<String> children;
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ children = getZooKeeper(info).getChildren(source, false);
+ break;
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+ retry.waitForNextAttempt();
+ }
+ for (String child : children)
+ recursiveCopyPersistent(info, source + "/" + child, destination + "/" + child, policy);
+ }
}
}
- public static boolean putPrivatePersistentData(ZooKeeper zk, String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
- return putData(zk, zPath, data, CreateMode.PERSISTENT, -1, policy, PRIVATE);
+ public static boolean putPrivatePersistentData(ZooKeeperConnectionInfo info, String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException,
+ InterruptedException {
+ return putData(info, zPath, data, CreateMode.PERSISTENT, -1, policy, PRIVATE);
}
- public static String putPersistentSequential(ZooKeeper zk, String zPath, byte[] data) throws KeeperException, InterruptedException {
+ public static String putPersistentSequential(ZooKeeperConnectionInfo info, String zPath, byte[] data) throws KeeperException, InterruptedException {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.PERSISTENT_SEQUENTIAL);
+ return getZooKeeper(info).create(zPath, data, ZooUtil.PUBLIC, CreateMode.PERSISTENT_SEQUENTIAL);
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -341,15 +376,14 @@ public class ZooUtil {
}
}
- public static String putEphemeralData(ZooKeeper zk, String zPath, byte[] data) throws KeeperException, InterruptedException {
+ public static String putEphemeralData(ZooKeeperConnectionInfo info, String zPath, byte[] data) throws KeeperException, InterruptedException {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL);
+ return getZooKeeper(info).create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL);
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -360,15 +394,14 @@ public class ZooUtil {
}
}
- public static String putEphemeralSequential(ZooKeeper zk, String zPath, byte[] data) throws KeeperException, InterruptedException {
+ public static String putEphemeralSequential(ZooKeeperConnectionInfo info, String zPath, byte[] data) throws KeeperException, InterruptedException {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL_SEQUENTIAL);
+ return getZooKeeper(info).create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL_SEQUENTIAL);
} catch (KeeperException e) {
final Code c = e.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, e);
} else {
throw e;
@@ -395,12 +428,11 @@ public class ZooUtil {
return zc.get(path + "/" + lockNode);
}
- public static boolean isLockHeld(ZooKeeper zk, LockID lid) throws KeeperException, InterruptedException {
+ public static boolean isLockHeld(ZooKeeperConnectionInfo info, LockID lid) throws KeeperException, InterruptedException {
final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
- // TODO push down retry to getChildren and exists
- List<String> children = zk.getChildren(lid.path, false);
+ List<String> children = getZooKeeper(info).getChildren(lid.path, false);
if (children.size() == 0) {
return false;
@@ -412,12 +444,11 @@ public class ZooUtil {
if (!lid.node.equals(lockNode))
return false;
- Stat stat = zk.exists(lid.path + "/" + lid.node, false);
+ Stat stat = getZooKeeper(info).exists(lid.path + "/" + lid.node, false);
return stat != null && stat.getEphemeralOwner() == lid.eid;
} catch (KeeperException ex) {
final Code c = ex.code();
if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
- // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
retryOrThrow(retry, ex);
}
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1ce12aea/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java b/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
index 5cbffc3..fcecc37 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
@@ -83,7 +83,7 @@ import com.beust.jcommander.Parameter;
/**
* This class is used to setup the directory structure and the root tablet to get an instance started
- *
+ *
*/
public class Initialize {
private static final Logger log = Logger.getLogger(Initialize.class);
@@ -101,7 +101,7 @@ public class Initialize {
/**
* Sets this class's ZooKeeper reader/writer.
- *
+ *
* @param izoo
* reader/writer
*/
@@ -111,7 +111,7 @@ public class Initialize {
/**
* Gets this class's ZooKeeper reader/writer.
- *
+ *
* @return reader/writer
*/
static IZooReaderWriter getZooReaderWriter() {
@@ -421,8 +421,8 @@ public class Initialize {
private static void initZooKeeper(Opts opts, String uuid, String instanceNamePath, Path rootTablet) throws KeeperException, InterruptedException {
// setup basic data in zookeeper
- ZooUtil.putPersistentData(zoo.getZooKeeper(), Constants.ZROOT, new byte[0], -1, NodeExistsPolicy.SKIP, Ids.OPEN_ACL_UNSAFE);
- ZooUtil.putPersistentData(zoo.getZooKeeper(), Constants.ZROOT + Constants.ZINSTANCES, new byte[0], -1, NodeExistsPolicy.SKIP, Ids.OPEN_ACL_UNSAFE);
+ zoo.putPersistentData(Constants.ZROOT, new byte[0], -1, NodeExistsPolicy.SKIP, Ids.OPEN_ACL_UNSAFE);
+ zoo.putPersistentData(Constants.ZROOT + Constants.ZINSTANCES, new byte[0], -1, NodeExistsPolicy.SKIP, Ids.OPEN_ACL_UNSAFE);
// setup instance name
if (opts.clearInstanceName)
[06/16] git commit: ACCUMULO-3242 Add some tests for ZooReaderWriter
Posted by el...@apache.org.
ACCUMULO-3242 Add some tests for ZooReaderWriter
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/6e716364
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/6e716364
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/6e716364
Branch: refs/heads/master
Commit: 6e71636462b3a5886502afcaed008e78ced0b4ef
Parents: c023f74
Author: Josh Elser <el...@apache.org>
Authored: Sat Oct 18 14:17:21 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:16:04 2014 -0400
----------------------------------------------------------------------
.../accumulo/fate/zookeeper/ZooReader.java | 20 +-
.../fate/zookeeper/ZooReaderWriter.java | 6 +-
.../fate/zookeeper/ZooReaderWriterTest.java | 193 +++++++++++++++++++
3 files changed, 208 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/6e716364/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
index 994f395..fd7938a 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
@@ -33,7 +33,7 @@ public class ZooReader implements IZooReader {
protected String keepers;
protected int timeout;
- protected final RetryFactory retryFactory;
+ private final RetryFactory retryFactory;
protected ZooKeeper getSession(String keepers, int timeout, String scheme, byte[] auth) {
return ZooSession.getSession(keepers, timeout, scheme, auth);
@@ -43,6 +43,10 @@ public class ZooReader implements IZooReader {
return getSession(keepers, timeout, null, null);
}
+ protected RetryFactory getRetryFactory() {
+ return retryFactory;
+ }
+
protected void retryOrThrow(Retry retry, KeeperException e) throws KeeperException {
log.warn("Saw (possibly) transient exception communicating with ZooKeeper", e);
if (retry.canRetry()) {
@@ -61,7 +65,7 @@ public class ZooReader implements IZooReader {
@Override
public byte[] getData(String zPath, boolean watch, Stat stat) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().getData(zPath, watch, stat);
@@ -80,7 +84,7 @@ public class ZooReader implements IZooReader {
@Override
public Stat getStatus(String zPath) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().exists(zPath, false);
@@ -99,7 +103,7 @@ public class ZooReader implements IZooReader {
@Override
public Stat getStatus(String zPath, Watcher watcher) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().exists(zPath, watcher);
@@ -118,7 +122,7 @@ public class ZooReader implements IZooReader {
@Override
public List<String> getChildren(String zPath) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().getChildren(zPath, false);
@@ -137,7 +141,7 @@ public class ZooReader implements IZooReader {
@Override
public List<String> getChildren(String zPath, Watcher watcher) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().getChildren(zPath, watcher);
@@ -156,7 +160,7 @@ public class ZooReader implements IZooReader {
@Override
public boolean exists(String zPath) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().exists(zPath, false) != null;
@@ -175,7 +179,7 @@ public class ZooReader implements IZooReader {
@Override
public boolean exists(String zPath, Watcher watcher) throws KeeperException, InterruptedException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
return getZooKeeper().exists(zPath, watcher) != null;
http://git-wip-us.apache.org/repos/asf/accumulo/blob/6e716364/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
index b29b88a..79c2219 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
@@ -106,7 +106,7 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
@Override
public void delete(String path, int version) throws InterruptedException, KeeperException {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
while (true) {
try {
getZooKeeper().delete(path, version);
@@ -137,7 +137,7 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
public byte[] mutate(String zPath, byte[] createValue, List<ACL> acl, Mutator mutator) throws Exception {
if (createValue != null) {
while (true) {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
try {
getZooKeeper().create(zPath, createValue, acl, CreateMode.PERSISTENT);
return createValue;
@@ -157,7 +157,7 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
}
}
do {
- final Retry retry = retryFactory.create();
+ final Retry retry = getRetryFactory().create();
Stat stat = new Stat();
byte[] data = getData(zPath, false, stat);
data = mutator.mutate(data);
http://git-wip-us.apache.org/repos/asf/accumulo/blob/6e716364/fate/src/test/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriterTest.java
----------------------------------------------------------------------
diff --git a/fate/src/test/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriterTest.java b/fate/src/test/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriterTest.java
new file mode 100644
index 0000000..59fb498
--- /dev/null
+++ b/fate/src/test/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriterTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.accumulo.fate.zookeeper;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.accumulo.fate.zookeeper.IZooReaderWriter.Mutator;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.KeeperException.BadVersionException;
+import org.apache.zookeeper.KeeperException.Code;
+import org.apache.zookeeper.KeeperException.ConnectionLossException;
+import org.apache.zookeeper.KeeperException.NoNodeException;
+import org.apache.zookeeper.KeeperException.NodeExistsException;
+import org.apache.zookeeper.KeeperException.SessionExpiredException;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Stat;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ZooReaderWriterTest {
+
+ private ZooReaderWriter zrw;
+ private ZooKeeper zk;
+ private RetryFactory retryFactory;
+ private Retry retry;
+
+ @Before
+ public void setup() {
+ zk = EasyMock.createMock(ZooKeeper.class);
+ zrw = EasyMock.createMockBuilder(ZooReaderWriter.class).addMockedMethods("getRetryFactory", "getZooKeeper").createMock();
+ retryFactory = EasyMock.createMock(RetryFactory.class);
+ retry = EasyMock.createMock(Retry.class);
+
+ EasyMock.expect(zrw.getZooKeeper()).andReturn(zk).anyTimes();
+ EasyMock.expect(zrw.getRetryFactory()).andReturn(retryFactory).anyTimes();
+ EasyMock.expect(retryFactory.create()).andReturn(retry).anyTimes();
+ }
+
+ @Test(expected = NoNodeException.class)
+ public void testDeleteFailOnInitialNoNode() throws Exception {
+ final String path = "/foo";
+ final int version = -1;
+
+ zk.delete(path, version);
+ EasyMock.expectLastCall().andThrow(KeeperException.create(Code.NONODE));
+ EasyMock.expect(retry.hasRetried()).andReturn(false);
+
+ EasyMock.replay(zk, zrw, retryFactory, retry);
+
+ zrw.delete(path, version);
+ }
+
+ @Test
+ public void testDeleteFailOnRetry() throws Exception {
+ final String path = "/foo";
+ final int version = -1;
+
+ zk.delete(path, version);
+ EasyMock.expectLastCall().andThrow(KeeperException.create(Code.CONNECTIONLOSS));
+ EasyMock.expect(retry.canRetry()).andReturn(true);
+ retry.useRetry();
+ EasyMock.expectLastCall().once();
+ retry.waitForNextAttempt();
+ EasyMock.expectLastCall().once();
+ zk.delete(path, version);
+ EasyMock.expectLastCall().andThrow(KeeperException.create(Code.NONODE));
+ EasyMock.expect(retry.hasRetried()).andReturn(true);
+
+ EasyMock.replay(zk, zrw, retryFactory, retry);
+
+ zrw.delete(path, version);
+
+ EasyMock.verify(zk, zrw, retryFactory, retry);
+ }
+
+ @Test(expected = SessionExpiredException.class)
+ public void testMutateNodeCreationFails() throws Exception {
+ final String path = "/foo";
+ final byte[] value = new byte[]{0};
+ final List<ACL> acls = Collections.<ACL> emptyList();
+ Mutator mutator = new Mutator() {
+ @Override
+ public byte[] mutate(byte[] currentValue) throws Exception {
+ return new byte[] {1};
+ }
+ };
+
+ zk.create(path, value, acls, CreateMode.PERSISTENT);
+ EasyMock.expectLastCall().andThrow(new SessionExpiredException()).once();
+ EasyMock.expect(retry.canRetry()).andReturn(false);
+ EasyMock.expect(retry.retriesCompleted()).andReturn(1l).once();
+
+ EasyMock.replay(zk, zrw, retryFactory, retry);
+
+ zrw.mutate(path, value, acls, mutator);
+ }
+
+ @Test
+ public void testMutateWithBadVersion() throws Exception {
+ final String path = "/foo";
+ final byte[] value = new byte[] {0};
+ final List<ACL> acls = Collections.<ACL> emptyList();
+ final byte[] mutatedBytes = new byte[] {1};
+ Mutator mutator = new Mutator() {
+ @Override
+ public byte[] mutate(byte[] currentValue) throws Exception {
+ return mutatedBytes;
+ }
+ };
+
+ Method getDataMethod = ZooReaderWriter.class.getMethod("getData", String.class, boolean.class, Stat.class);
+ zrw = EasyMock.createMockBuilder(ZooReaderWriter.class).addMockedMethods("getRetryFactory", "getZooKeeper").addMockedMethod(getDataMethod).createMock();
+ EasyMock.expect(zrw.getRetryFactory()).andReturn(retryFactory).anyTimes();
+ EasyMock.expect(zrw.getZooKeeper()).andReturn(zk).anyTimes();
+
+ Stat stat = new Stat();
+
+ zk.create(path, value, acls, CreateMode.PERSISTENT);
+ EasyMock.expectLastCall().andThrow(new NodeExistsException()).once();
+ EasyMock.expect(zrw.getData(path, false, stat)).andReturn(new byte[] {3}).times(2);
+ // BadVersionException should retry
+ EasyMock.expect(zk.setData(path, mutatedBytes, 0)).andThrow(new BadVersionException());
+ // Let 2nd setData succeed
+ EasyMock.expect(zk.setData(path, mutatedBytes, 0)).andReturn(null);
+
+ EasyMock.replay(zk, zrw, retryFactory, retry);
+
+ Assert.assertArrayEquals(new byte[] {1}, zrw.mutate(path, value, acls, mutator));
+
+ EasyMock.verify(zk, zrw, retryFactory, retry);
+ }
+
+ @Test
+ public void testMutateWithRetryOnSetData() throws Exception {
+ final String path = "/foo";
+ final byte[] value = new byte[] {0};
+ final List<ACL> acls = Collections.<ACL> emptyList();
+ final byte[] mutatedBytes = new byte[] {1};
+ Mutator mutator = new Mutator() {
+ @Override
+ public byte[] mutate(byte[] currentValue) throws Exception {
+ return mutatedBytes;
+ }
+ };
+
+ Method getDataMethod = ZooReaderWriter.class.getMethod("getData", String.class, boolean.class, Stat.class);
+ zrw = EasyMock.createMockBuilder(ZooReaderWriter.class).addMockedMethods("getRetryFactory", "getZooKeeper").addMockedMethod(getDataMethod).createMock();
+ EasyMock.expect(zrw.getRetryFactory()).andReturn(retryFactory).anyTimes();
+ EasyMock.expect(zrw.getZooKeeper()).andReturn(zk).anyTimes();
+
+ Stat stat = new Stat();
+
+ zk.create(path, value, acls, CreateMode.PERSISTENT);
+ EasyMock.expectLastCall().andThrow(new NodeExistsException()).once();
+ EasyMock.expect(zrw.getData(path, false, stat)).andReturn(new byte[] {3}).times(2);
+ // BadVersionException should retry
+ EasyMock.expect(zk.setData(path, mutatedBytes, 0)).andThrow(new ConnectionLossException());
+
+ EasyMock.expect(retry.canRetry()).andReturn(true);
+ retry.useRetry();
+ EasyMock.expectLastCall();
+ retry.waitForNextAttempt();
+ EasyMock.expectLastCall();
+ // Let 2nd setData succeed
+ EasyMock.expect(zk.setData(path, mutatedBytes, 0)).andReturn(null);
+
+ EasyMock.replay(zk, zrw, retryFactory, retry);
+
+ Assert.assertArrayEquals(new byte[] {1}, zrw.mutate(path, value, acls, mutator));
+
+ EasyMock.verify(zk, zrw, retryFactory, retry);
+ }
+}
[07/16] git commit: ACCUMULO-3242 Add some tests for Retry
Posted by el...@apache.org.
ACCUMULO-3242 Add some tests for Retry
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/1636055a
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/1636055a
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/1636055a
Branch: refs/heads/1.6
Commit: 1636055ac6d8d5fecae9e292be283b864d3d4341
Parents: 1ce12ae
Author: Josh Elser <el...@apache.org>
Authored: Sat Oct 18 16:18:41 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:16:04 2014 -0400
----------------------------------------------------------------------
.../apache/accumulo/fate/zookeeper/Retry.java | 27 +++-
.../accumulo/fate/zookeeper/RetryTest.java | 127 +++++++++++++++++++
2 files changed, 152 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1636055a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
index 63aa902..7bfaba6 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
@@ -24,7 +24,7 @@ import org.apache.log4j.Logger;
public class Retry {
private static final Logger log = Logger.getLogger(Retry.class);
- private final long maxRetries, maxWait, waitIncrement;
+ private long maxRetries, maxWait, waitIncrement;
private long retriesDone, currentWait;
/**
@@ -45,6 +45,26 @@ public class Retry {
this.currentWait = startWait;
}
+ // Visible for testing
+ void setMaxRetries(long maxRetries) {
+ this.maxRetries = maxRetries;
+ }
+
+ // Visible for testing
+ void setStartWait(long startWait) {
+ this.currentWait = startWait;
+ }
+
+ // Visible for testing
+ void setWaitIncrement(long waitIncrement) {
+ this.waitIncrement = waitIncrement;
+ }
+
+ // Visible for testing
+ void setMaxWait(long maxWait) {
+ this.maxWait = maxWait;
+ }
+
public boolean canRetry() {
return retriesDone < maxRetries;
}
@@ -67,8 +87,11 @@ public class Retry {
public void waitForNextAttempt() throws InterruptedException {
log.debug("Sleeping for " + currentWait + "ms before retrying operation");
- Thread.sleep(currentWait);
+ sleep(currentWait);
currentWait = Math.min(maxWait, currentWait + waitIncrement);
}
+ protected void sleep(long wait) throws InterruptedException {
+ Thread.sleep(wait);
+ }
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/1636055a/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryTest.java
----------------------------------------------------------------------
diff --git a/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryTest.java b/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryTest.java
new file mode 100644
index 0000000..e37af01
--- /dev/null
+++ b/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.accumulo.fate.zookeeper;
+
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class RetryTest {
+
+ private Retry retry;
+ long initialWait = 1000l, waitIncrement = 1000l, maxRetries = 5;
+
+ @Before
+ public void setup() {
+ retry = new Retry(maxRetries, initialWait, waitIncrement, maxRetries * 1000l);
+ }
+
+ @Test
+ public void canRetryDoesntAlterState() {
+ for (int i = 0; i < maxRetries + 1; i++) {
+ Assert.assertTrue(retry.canRetry());
+ }
+ }
+
+ @Test
+ public void hasRetriedAfterUse() {
+ Assert.assertFalse(retry.hasRetried());
+ retry.useRetry();
+ Assert.assertTrue(retry.hasRetried());
+ }
+
+ @Test
+ public void retriesAreCompleted() {
+ for (int i = 0; i < maxRetries; i++) {
+ Assert.assertEquals(i, retry.retriesCompleted());
+ // canRetry doesn't alter retry's state
+ retry.canRetry();
+ Assert.assertEquals(i, retry.retriesCompleted());
+ // Using the retry will increase the internal count
+ retry.useRetry();
+ Assert.assertEquals(i + 1, retry.retriesCompleted());
+ }
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void usingNonExistentRetryFails() {
+ for (int i = 0; i < maxRetries; i++) {
+ Assert.assertTrue(retry.canRetry());
+ retry.useRetry();
+ }
+ Assert.assertFalse(retry.canRetry());
+ // Calling useRetry when canRetry returns false throws an exception
+ retry.useRetry();
+ }
+
+ @Test
+ public void testWaitIncrement() throws InterruptedException {
+ retry = EasyMock.createMockBuilder(Retry.class).addMockedMethod("sleep").createStrictMock();
+ retry.setMaxRetries(maxRetries);
+ retry.setStartWait(initialWait);
+ retry.setWaitIncrement(waitIncrement);
+ retry.setMaxWait(maxRetries * 1000l);
+
+ long currentWait = initialWait;
+ for (int i = 1; i <= maxRetries; i++) {
+ retry.sleep(currentWait);
+ EasyMock.expectLastCall();
+ currentWait += waitIncrement;
+ }
+
+ EasyMock.replay(retry);
+
+ while (retry.canRetry()) {
+ retry.useRetry();
+ retry.waitForNextAttempt();
+ }
+
+ EasyMock.verify(retry);
+ }
+
+ @Test
+ public void testBoundedWaitIncrement() throws InterruptedException {
+ retry = EasyMock.createMockBuilder(Retry.class).addMockedMethod("sleep").createStrictMock();
+ retry.setMaxRetries(maxRetries);
+ retry.setStartWait(initialWait);
+ retry.setWaitIncrement(waitIncrement);
+ // Make the last retry not increment in length
+ retry.setMaxWait((maxRetries - 1) * 1000l);
+
+ long currentWait = initialWait;
+ for (int i = 1; i <= maxRetries; i++) {
+ retry.sleep(currentWait);
+ EasyMock.expectLastCall();
+ if (i < maxRetries - 1) {
+ currentWait += waitIncrement;
+ }
+ }
+
+ EasyMock.replay(retry);
+
+ while (retry.canRetry()) {
+ retry.useRetry();
+ retry.waitForNextAttempt();
+ }
+
+ EasyMock.verify(retry);
+ }
+}
[04/16] git commit: ACCUMULO-3242 Add proper retry logic to ZooReader,
ZooReaderWriter and ZooUtil removing the RetryingInstance.
Posted by el...@apache.org.
ACCUMULO-3242 Add proper retry logic to ZooReader, ZooReaderWriter and ZooUtil removing the RetryingInstance.
The RetryingInvocationHandler was a nice way to encapsulate retry logic
on a ZooKeeper; however it fails when you actually need to do additional
handling of the KeeperException. Removing the retrying/non-retrying logic
also simplifies methods that the clients can interact with.
ZooUtil still has some unaddressed issues, but I left some TODOs
in place to mark what still needs to be fixed, usually WRT to
session expirations.
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/c023f74e
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/c023f74e
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/c023f74e
Branch: refs/heads/master
Commit: c023f74e4329b8c764c46f9468681b71762e976a
Parents: 6ad16a9
Author: Josh Elser <el...@apache.org>
Authored: Fri Oct 17 01:22:15 2014 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Sun Oct 19 20:15:59 2014 -0400
----------------------------------------------------------------------
.../accumulo/fate/zookeeper/IZooReader.java | 20 +-
.../apache/accumulo/fate/zookeeper/Retry.java | 74 +++++
.../accumulo/fate/zookeeper/RetryFactory.java | 36 +++
.../zookeeper/RetryingInvocationHandler.java | 63 ----
.../accumulo/fate/zookeeper/ZooQueueLock.java | 20 +-
.../accumulo/fate/zookeeper/ZooReader.java | 133 +++++++-
.../fate/zookeeper/ZooReaderWriter.java | 129 +++++---
.../accumulo/fate/zookeeper/ZooSession.java | 42 +--
.../apache/accumulo/fate/zookeeper/ZooUtil.java | 301 ++++++++++++++-----
.../RetryingInvocationHandlerTest.java | 87 ------
.../org/apache/accumulo/server/Accumulo.java | 2 +-
.../accumulo/server/master/LiveTServerSet.java | 2 +-
.../security/handler/ZKAuthenticator.java | 42 +--
.../server/security/handler/ZKAuthorizor.java | 8 +-
.../server/security/handler/ZKPermHandler.java | 42 +--
.../accumulo/server/tables/TableManager.java | 16 +-
.../server/tablets/UniqueNameAllocator.java | 2 +-
.../accumulo/server/zookeeper/ZooQueueLock.java | 8 +-
.../server/zookeeper/ZooReaderWriter.java | 45 ---
.../zookeeper/ZooReaderWriterFactory.java | 22 --
.../java/org/apache/accumulo/master/Master.java | 4 +-
.../master/tableOps/CancelCompactions.java | 34 +--
.../accumulo/master/tableOps/CompactRange.java | 6 +-
.../master/tableOps/RenameNamespace.java | 2 +-
.../accumulo/master/tableOps/RenameTable.java | 2 +-
.../apache/accumulo/master/tableOps/Utils.java | 12 +-
.../apache/accumulo/master/util/FateAdmin.java | 2 +-
.../org/apache/accumulo/tserver/Tablet.java | 10 +-
28 files changed, 688 insertions(+), 478 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReader.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReader.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReader.java
index 0610e79..610b1bd 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReader.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/IZooReader.java
@@ -23,21 +23,23 @@ import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.data.Stat;
public interface IZooReader {
-
+
byte[] getData(String zPath, Stat stat) throws KeeperException, InterruptedException;
-
+
+ byte[] getData(String zPath, boolean watch, Stat stat) throws KeeperException, InterruptedException;
+
Stat getStatus(String zPath) throws KeeperException, InterruptedException;
-
+
Stat getStatus(String zPath, Watcher watcher) throws KeeperException, InterruptedException;
-
+
List<String> getChildren(String zPath) throws KeeperException, InterruptedException;
-
+
List<String> getChildren(String zPath, Watcher watcher) throws KeeperException, InterruptedException;
-
+
boolean exists(String zPath) throws KeeperException, InterruptedException;
-
+
boolean exists(String zPath, Watcher watcher) throws KeeperException, InterruptedException;
-
+
void sync(final String path) throws KeeperException, InterruptedException;
-
+
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
new file mode 100644
index 0000000..4a37172
--- /dev/null
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/Retry.java
@@ -0,0 +1,74 @@
+/*
+ * 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.accumulo.fate.zookeeper;
+
+import org.apache.log4j.Logger;
+
+/**
+ *
+ */
+public class Retry {
+ private static final Logger log = Logger.getLogger(Retry.class);
+
+ private final long maxRetries, maxWait, waitIncrement;
+ private long retriesDone, currentWait;
+
+ /**
+ * @param maxRetries
+ * Maximum times to retry
+ * @param startWait
+ * The amount of time (ms) to wait for the initial retry
+ * @param maxWait
+ * The maximum wait (ms)
+ * @param waitIncrement
+ * The amount of time (ms) to increment next wait time by
+ */
+ public Retry(long maxRetries, long startWait, long maxWait, long waitIncrement) {
+ this.maxRetries = maxRetries;
+ this.maxWait = maxWait;
+ this.waitIncrement = waitIncrement;
+ this.retriesDone = 0l;
+ this.currentWait = startWait;
+ }
+
+ public boolean canRetry() {
+ return retriesDone < maxRetries;
+ }
+
+ public void useRetry() {
+ if (!canRetry()) {
+ throw new IllegalStateException("No retries left");
+ }
+
+ retriesDone++;
+ }
+
+ public boolean hasRetried() {
+ return retriesDone > 0;
+ }
+
+ public long retriesCompleted() {
+ return retriesDone;
+ }
+
+ public void waitForNextAttempt() throws InterruptedException {
+ log.debug("Sleeping for " + currentWait + "ms before retrying operation");
+ Thread.sleep(currentWait);
+ currentWait = Math.min(maxWait, currentWait + waitIncrement);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
new file mode 100644
index 0000000..3fcb738
--- /dev/null
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryFactory.java
@@ -0,0 +1,36 @@
+/*
+ * 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.accumulo.fate.zookeeper;
+
+/**
+ *
+ */
+public class RetryFactory {
+
+ private final long maxRetries, startWait, maxWait, waitIncrement;
+
+ public RetryFactory(long maxRetries, long startWait, long maxWait, long waitIncrement) {
+ this.maxRetries = maxRetries;
+ this.startWait = startWait;
+ this.maxWait = maxWait;
+ this.waitIncrement = waitIncrement;
+ }
+
+ public Retry create() {
+ return new Retry(maxRetries, startWait, maxWait, waitIncrement);
+ }
+}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandler.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandler.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandler.java
deleted file mode 100644
index 4597036..0000000
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandler.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.accumulo.fate.zookeeper;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import org.apache.accumulo.fate.util.UtilWaitThread;
-import org.apache.log4j.Logger;
-import org.apache.zookeeper.KeeperException;
-
-/**
- * An invocation handler for ZooKeeper reader/writers that retries calls that fail due to connection loss.
- */
-public class RetryingInvocationHandler implements InvocationHandler {
- private final IZooReaderWriter zrw;
-
- /**
- * Creates a new invocation handler.
- *
- * @param zrw
- * ZooKeeper reader/writer being handled
- */
- public RetryingInvocationHandler(IZooReaderWriter zrw) {
- this.zrw = zrw;
- }
-
- private static final long INITIAL_RETRY_TIME = 250L;
- private static final long RETRY_INCREMENT = 250L;
- private static final long MAXIMUM_RETRY_TIME = 5000L;
-
- @Override
- public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
- long retryTime = INITIAL_RETRY_TIME;
- while (true) {
- try {
- return method.invoke(zrw, args);
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof KeeperException.ConnectionLossException) {
- Logger.getLogger(ZooReaderWriter.class).warn("Error connecting to zookeeper, will retry in " + String.format("%.2f secs", retryTime / 1000.0), e.getCause());
- UtilWaitThread.sleep(retryTime);
- retryTime = Math.min(MAXIMUM_RETRY_TIME, retryTime + RETRY_INCREMENT);
- } else {
- throw e.getCause();
- }
- }
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooQueueLock.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooQueueLock.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooQueueLock.java
index f30cda3..f9195f3 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooQueueLock.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooQueueLock.java
@@ -29,26 +29,26 @@ import org.apache.zookeeper.KeeperException.NoNodeException;
import org.apache.zookeeper.KeeperException.NotEmptyException;
public class ZooQueueLock implements QueueLock {
-
+
private static final String PREFIX = "lock-";
-
+
// private static final Logger log = Logger.getLogger(ZooQueueLock.class);
-
+
private IZooReaderWriter zoo;
private String path;
private boolean ephemeral;
-
+
public ZooQueueLock(String zookeepers, int timeInMillis, String scheme, byte[] auth, String path, boolean ephemeral) throws KeeperException,
InterruptedException {
- this(ZooReaderWriter.getRetryingInstance(zookeepers, timeInMillis, scheme, auth), path, ephemeral);
+ this(ZooReaderWriter.getInstance(zookeepers, timeInMillis, scheme, auth), path, ephemeral);
}
-
+
protected ZooQueueLock(IZooReaderWriter zrw, String path, boolean ephemeral) {
this.zoo = zrw;
this.path = path;
this.ephemeral = ephemeral;
}
-
+
@Override
public long addEntry(byte[] data) {
String newPath;
@@ -72,7 +72,7 @@ public class ZooQueueLock implements QueueLock {
throw new RuntimeException(ex);
}
}
-
+
@Override
public SortedMap<Long,byte[]> getEarlierEntries(long entry) {
SortedMap<Long,byte[]> result = new TreeMap<Long,byte[]>();
@@ -83,7 +83,7 @@ public class ZooQueueLock implements QueueLock {
} catch (KeeperException.NoNodeException ex) {
// the path does not exist (it was deleted or not created yet), that is ok there are no earlier entries then
}
-
+
for (String name : children) {
// this try catch must be done inside the loop because some subset of the children may exist
try {
@@ -100,7 +100,7 @@ public class ZooQueueLock implements QueueLock {
}
return result;
}
-
+
@Override
public void removeEntry(long entry) {
try {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
index 60660d6..994f395 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java
@@ -20,6 +20,7 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.log4j.Logger;
import org.apache.zookeeper.AsyncCallback.VoidCallback;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.Code;
@@ -28,8 +29,11 @@ import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
public class ZooReader implements IZooReader {
+ private static final Logger log = Logger.getLogger(ZooReader.class);
+
protected String keepers;
protected int timeout;
+ protected final RetryFactory retryFactory;
protected ZooKeeper getSession(String keepers, int timeout, String scheme, byte[] auth) {
return ZooSession.getSession(keepers, timeout, scheme, auth);
@@ -39,39 +43,153 @@ public class ZooReader implements IZooReader {
return getSession(keepers, timeout, null, null);
}
+ protected void retryOrThrow(Retry retry, KeeperException e) throws KeeperException {
+ log.warn("Saw (possibly) transient exception communicating with ZooKeeper", e);
+ if (retry.canRetry()) {
+ retry.useRetry();
+ return;
+ }
+
+ log.error("Retry attempts (" + retry.retriesCompleted() + ") exceeded trying to communicate with ZooKeeper");
+ throw e;
+ }
+
@Override
public byte[] getData(String zPath, Stat stat) throws KeeperException, InterruptedException {
- return getZooKeeper().getData(zPath, false, stat);
+ return getData(zPath, false, stat);
+ }
+
+ @Override
+ public byte[] getData(String zPath, boolean watch, Stat stat) throws KeeperException, InterruptedException {
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().getData(zPath, watch, stat);
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
public Stat getStatus(String zPath) throws KeeperException, InterruptedException {
- return getZooKeeper().exists(zPath, false);
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().exists(zPath, false);
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
public Stat getStatus(String zPath, Watcher watcher) throws KeeperException, InterruptedException {
- return getZooKeeper().exists(zPath, watcher);
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().exists(zPath, watcher);
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
public List<String> getChildren(String zPath) throws KeeperException, InterruptedException {
- return getZooKeeper().getChildren(zPath, false);
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().getChildren(zPath, false);
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
public List<String> getChildren(String zPath, Watcher watcher) throws KeeperException, InterruptedException {
- return getZooKeeper().getChildren(zPath, watcher);
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().getChildren(zPath, watcher);
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
public boolean exists(String zPath) throws KeeperException, InterruptedException {
- return getZooKeeper().exists(zPath, false) != null;
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().exists(zPath, false) != null;
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
public boolean exists(String zPath, Watcher watcher) throws KeeperException, InterruptedException {
- return getZooKeeper().exists(zPath, watcher) != null;
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ return getZooKeeper().exists(zPath, watcher) != null;
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
@Override
@@ -101,5 +219,6 @@ public class ZooReader implements IZooReader {
public ZooReader(String keepers, int timeout) {
this.keepers = keepers;
this.timeout = timeout;
+ this.retryFactory = new RetryFactory(10l, 250l, 250l, 5000l);
}
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
index 1f0ae14..b29b88a 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java
@@ -16,31 +16,29 @@
*/
package org.apache.accumulo.fate.zookeeper;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Proxy;
import java.security.SecurityPermission;
import java.util.Arrays;
import java.util.List;
import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeMissingPolicy;
+import org.apache.log4j.Logger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
-import org.apache.zookeeper.KeeperException.BadVersionException;
-import org.apache.zookeeper.KeeperException.NodeExistsException;
+import org.apache.zookeeper.KeeperException.Code;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
-
+ private static final Logger log = Logger.getLogger(ZooReaderWriter.class);
+
private static SecurityPermission ZOOWRITER_PERMISSION = new SecurityPermission("zookeeperWriterPermission");
-
+
private static ZooReaderWriter instance = null;
- private static IZooReaderWriter retryingInstance = null;
private final String scheme;
private final byte[] auth;
-
+
@Override
public ZooKeeper getZooKeeper() {
SecurityManager sm = System.getSecurityManager();
@@ -49,127 +47,158 @@ public class ZooReaderWriter extends ZooReader implements IZooReaderWriter {
}
return getSession(keepers, timeout, scheme, auth);
}
-
+
public ZooReaderWriter(String string, int timeInMillis, String scheme, byte[] auth) {
super(string, timeInMillis);
this.scheme = scheme;
this.auth = Arrays.copyOf(auth, auth.length);
}
-
+
@Override
public void recursiveDelete(String zPath, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
ZooUtil.recursiveDelete(getZooKeeper(), zPath, policy);
}
-
+
@Override
public void recursiveDelete(String zPath, int version, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
ZooUtil.recursiveDelete(getZooKeeper(), zPath, version, policy);
}
-
+
/**
* Create a persistent node with the default ACL
- *
+ *
* @return true if the node was created or altered; false if it was skipped
*/
@Override
public boolean putPersistentData(String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
return ZooUtil.putPersistentData(getZooKeeper(), zPath, data, policy);
}
-
+
@Override
public boolean putPrivatePersistentData(String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
return ZooUtil.putPrivatePersistentData(getZooKeeper(), zPath, data, policy);
}
-
+
@Override
public void putPersistentData(String zPath, byte[] data, int version, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
ZooUtil.putPersistentData(getZooKeeper(), zPath, data, version, policy);
}
-
+
@Override
public String putPersistentSequential(String zPath, byte[] data) throws KeeperException, InterruptedException {
return ZooUtil.putPersistentSequential(getZooKeeper(), zPath, data);
}
-
+
@Override
public String putEphemeralData(String zPath, byte[] data) throws KeeperException, InterruptedException {
return ZooUtil.putEphemeralData(getZooKeeper(), zPath, data);
}
-
+
@Override
public String putEphemeralSequential(String zPath, byte[] data) throws KeeperException, InterruptedException {
return ZooUtil.putEphemeralSequential(getZooKeeper(), zPath, data);
}
-
+
@Override
public void recursiveCopyPersistent(String source, String destination, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
ZooUtil.recursiveCopyPersistent(getZooKeeper(), source, destination, policy);
}
-
+
@Override
public void delete(String path, int version) throws InterruptedException, KeeperException {
- getZooKeeper().delete(path, version);
+ final Retry retry = retryFactory.create();
+ while (true) {
+ try {
+ getZooKeeper().delete(path, version);
+ return;
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.NONODE) {
+ if (retry.hasRetried()) {
+ // A retried delete could have deleted the node, assume that was the case
+ log.debug("Delete saw no node on a retry. Assuming node was deleted");
+ return;
+ }
+
+ throw e;
+ } else if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ // retry if we have more attempts to do so
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
-
+
@Override
public byte[] mutate(String zPath, byte[] createValue, List<ACL> acl, Mutator mutator) throws Exception {
if (createValue != null) {
- try {
- getZooKeeper().create(zPath, createValue, acl, CreateMode.PERSISTENT);
- return createValue;
- } catch (NodeExistsException ex) {
- // expected
+ while (true) {
+ final Retry retry = retryFactory.create();
+ try {
+ getZooKeeper().create(zPath, createValue, acl, CreateMode.PERSISTENT);
+ return createValue;
+ } catch (KeeperException ex) {
+ final Code code = ex.code();
+ if (code == Code.NODEEXISTS) {
+ // expected
+ break;
+ } else if (code == Code.OPERATIONTIMEOUT || code == Code.CONNECTIONLOSS || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, ex);
+ } else {
+ throw ex;
+ }
+ }
+
+ retry.waitForNextAttempt();
}
}
do {
+ final Retry retry = retryFactory.create();
Stat stat = new Stat();
- byte[] data = getZooKeeper().getData(zPath, false, stat);
+ byte[] data = getData(zPath, false, stat);
data = mutator.mutate(data);
if (data == null)
return data;
try {
getZooKeeper().setData(zPath, data, stat.getVersion());
return data;
- } catch (BadVersionException ex) {
- //
+ } catch (KeeperException ex) {
+ final Code code = ex.code();
+ if (code == Code.BADVERSION) {
+ // Retry, but don't increment. This makes it backwards compatible with the infinite
+ // loop that previously happened. I'm not sure if that's really desirable though.
+ } else if (code == Code.OPERATIONTIMEOUT || code == Code.CONNECTIONLOSS || code == Code.SESSIONEXPIRED) {
+ retryOrThrow(retry, ex);
+ retry.waitForNextAttempt();
+ } else {
+ throw ex;
+ }
}
} while (true);
}
-
+
public static synchronized ZooReaderWriter getInstance(String zookeepers, int timeInMillis, String scheme, byte[] auth) {
if (instance == null)
instance = new ZooReaderWriter(zookeepers, timeInMillis, scheme, auth);
return instance;
}
-
- /**
- * get an instance that retries when zookeeper connection errors occur
- *
- * @return an instance that retries when Zookeeper connection errors occur.
- */
- public static synchronized IZooReaderWriter getRetryingInstance(String zookeepers, int timeInMillis, String scheme, byte[] auth) {
-
- if (retryingInstance == null) {
- IZooReaderWriter inst = getInstance(zookeepers, timeInMillis, scheme, auth);
- InvocationHandler ih = new RetryingInvocationHandler(inst);
- retryingInstance = (IZooReaderWriter) Proxy.newProxyInstance(ZooReaderWriter.class.getClassLoader(), new Class[] {IZooReaderWriter.class}, ih);
- }
-
- return retryingInstance;
- }
-
+
@Override
public boolean isLockHeld(ZooUtil.LockID lockID) throws KeeperException, InterruptedException {
return ZooUtil.isLockHeld(getZooKeeper(), lockID);
}
-
+
@Override
public void mkdirs(String path) throws KeeperException, InterruptedException {
if (path.equals(""))
return;
if (!path.startsWith("/"))
throw new IllegalArgumentException(path + "does not start with /");
- if (getZooKeeper().exists(path, false) != null)
+ if (exists(path))
return;
String parent = path.substring(0, path.lastIndexOf("/"));
mkdirs(parent);
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooSession.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooSession.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooSession.java
index 33bd77b..b6890c6 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooSession.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooSession.java
@@ -33,7 +33,7 @@ import org.apache.zookeeper.ZooKeeper.States;
public class ZooSession {
private static final Charset UTF8 = Charset.forName("UTF-8");
-
+
public static class ZooSessionShutdownException extends RuntimeException {
private static final long serialVersionUID = 1L;
@@ -41,31 +41,32 @@ public class ZooSession {
}
private static final Logger log = Logger.getLogger(ZooSession.class);
-
+
private static class ZooSessionInfo {
public ZooSessionInfo(ZooKeeper zooKeeper, ZooWatcher watcher) {
this.zooKeeper = zooKeeper;
}
-
+
ZooKeeper zooKeeper;
}
-
+
private static Map<String,ZooSessionInfo> sessions = new HashMap<String,ZooSessionInfo>();
-
+
private static String sessionKey(String keepers, int timeout, String scheme, byte[] auth) {
return keepers + ":" + timeout + ":" + (scheme == null ? "" : scheme) + ":" + (auth == null ? "" : new String(auth, UTF8));
}
-
+
private static class ZooWatcher implements Watcher {
-
+
+ @Override
public void process(WatchedEvent event) {
if (event.getState() == KeeperState.Expired) {
log.debug("Session expired, state of current session : " + event.getState());
}
}
-
+
}
-
+
/**
* @param host comma separated list of zk servers
* @param timeout in milliseconds
@@ -79,9 +80,9 @@ public class ZooSession {
boolean tryAgain = true;
long sleepTime = 100;
ZooKeeper zooKeeper = null;
-
+
long startTime = System.currentTimeMillis();
-
+
while (tryAgain) {
try {
zooKeeper = new ZooKeeper(host, timeout, watcher);
@@ -94,7 +95,7 @@ public class ZooSession {
} else
UtilWaitThread.sleep(TIME_BETWEEN_CONNECT_CHECKS_MS);
}
-
+
} catch (IOException e) {
if (e instanceof UnknownHostException) {
/*
@@ -116,13 +117,13 @@ public class ZooSession {
if (System.currentTimeMillis() - startTime > 2 * timeout) {
throw new RuntimeException("Failed to connect to zookeeper (" + host + ") within 2x zookeeper timeout period " + timeout);
}
-
+
if (tryAgain) {
if (startTime + 2 * timeout < System.currentTimeMillis() + sleepTime + connectTimeWait)
sleepTime = startTime + 2 * timeout - System.currentTimeMillis() - connectTimeWait;
if (sleepTime < 0)
{
- connectTimeWait -= sleepTime;
+ connectTimeWait -= sleepTime;
sleepTime = 0;
}
UtilWaitThread.sleep(sleepTime);
@@ -130,31 +131,32 @@ public class ZooSession {
sleepTime = sleepTime + (long)(sleepTime * Math.random());
}
}
-
+
return zooKeeper;
}
-
+
public static synchronized ZooKeeper getSession(String zooKeepers, int timeout) {
return getSession(zooKeepers, timeout, null, null);
}
-
+
public static synchronized ZooKeeper getSession(String zooKeepers, int timeout, String scheme, byte[] auth) {
-
+
if (sessions == null)
throw new ZooSessionShutdownException();
String sessionKey = sessionKey(zooKeepers, timeout, scheme, auth);
-
+
// a read-only session can use a session with authorizations, so cache a copy for it w/out auths
String readOnlySessionKey = sessionKey(zooKeepers, timeout, null, null);
ZooSessionInfo zsi = sessions.get(sessionKey);
if (zsi != null && zsi.zooKeeper.getState() == States.CLOSED) {
+ log.debug("Removing closed ZooKeeper session to " + zooKeepers);
if (auth != null && sessions.get(readOnlySessionKey) == zsi)
sessions.remove(readOnlySessionKey);
zsi = null;
sessions.remove(sessionKey);
}
-
+
if (zsi == null) {
ZooWatcher watcher = new ZooWatcher();
log.debug("Connecting to " + zooKeepers + " with timeout " + timeout + " with auth");
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
----------------------------------------------------------------------
diff --git a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
index 5b856c0..e0d8831 100644
--- a/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
+++ b/fate/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java
@@ -21,12 +21,11 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import org.apache.accumulo.fate.util.UtilWaitThread;
+import org.apache.log4j.Logger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.Code;
import org.apache.zookeeper.KeeperException.NoNodeException;
-import org.apache.zookeeper.KeeperException.NodeExistsException;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooDefs.Perms;
import org.apache.zookeeper.ZooKeeper;
@@ -34,27 +33,29 @@ import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
public class ZooUtil {
+ private static final Logger log = Logger.getLogger(ZooUtil.class);
+
public enum NodeExistsPolicy {
SKIP, OVERWRITE, FAIL
}
-
+
public enum NodeMissingPolicy {
SKIP, CREATE, FAIL
}
-
+
public static class LockID {
public long eid;
public String path;
public String node;
-
+
public LockID(String root, String serializedLID) {
String sa[] = serializedLID.split("\\$");
int lastSlash = sa[0].lastIndexOf('/');
-
+
if (sa.length != 2 || lastSlash < 0) {
throw new IllegalArgumentException("Malformed serialized lock id " + serializedLID);
}
-
+
if (lastSlash == 0)
path = root;
else
@@ -62,37 +63,50 @@ public class ZooUtil {
node = sa[0].substring(lastSlash + 1);
eid = new BigInteger(sa[1], 16).longValue();
}
-
+
public LockID(String path, String node, long eid) {
this.path = path;
this.node = node;
this.eid = eid;
}
-
+
public String serialize(String root) {
-
+
return path.substring(root.length()) + "/" + node + "$" + Long.toHexString(eid);
}
-
+
@Override
public String toString() {
return " path = " + path + " node = " + node + " eid = " + Long.toHexString(eid);
}
}
-
+
public static final List<ACL> PRIVATE;
public static final List<ACL> PUBLIC;
+ private static final RetryFactory RETRY_FACTORY;
static {
PRIVATE = new ArrayList<ACL>();
PRIVATE.addAll(Ids.CREATOR_ALL_ACL);
PUBLIC = new ArrayList<ACL>();
PUBLIC.addAll(PRIVATE);
PUBLIC.add(new ACL(Perms.READ, Ids.ANYONE_ID_UNSAFE));
+ RETRY_FACTORY = new RetryFactory(10l, 250l, 250l, 5000l);
}
-
+
+ protected static void retryOrThrow(Retry retry, KeeperException e) throws KeeperException {
+ log.warn("Saw (possibly) transient exception communicating with ZooKeeper", e);
+ if (retry.canRetry()) {
+ retry.useRetry();
+ return;
+ }
+
+ log.error("Retry attempts (" + retry.retriesCompleted() + ") exceeded trying to communicate with ZooKeeper");
+ throw e;
+ }
+
/**
* This method will delete a node and all its children from zookeeper
- *
+ *
* @param zPath
* the path to delete
*/
@@ -100,82 +114,180 @@ public class ZooUtil {
if (policy.equals(NodeMissingPolicy.CREATE))
throw new IllegalArgumentException(policy.name() + " is invalid for this operation");
try {
- for (String child : zk.getChildren(zPath, false))
+ List<String> children;
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ children = zk.getChildren(zPath, false);
+ break;
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+ retry.waitForNextAttempt();
+ }
+ for (String child : children)
recursiveDelete(zk, zPath + "/" + child, NodeMissingPolicy.SKIP);
-
+
Stat stat;
- if ((stat = zk.exists(zPath, null)) != null)
- zk.delete(zPath, stat.getVersion());
+ while (true) {
+ try {
+ stat = zk.exists(zPath, null);
+ // Node exists
+ if (stat != null) {
+ try {
+ // Try to delete it
+ zk.delete(zPath, stat.getVersion());
+ return;
+ } catch (NoNodeException e) {
+ // If the node is gone now, it's ok if we have SKIP
+ if (policy.equals(NodeMissingPolicy.SKIP)) {
+ return;
+ }
+ throw e;
+ }
+ // Let other KeeperException bubble to the outer catch
+ }
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
} catch (KeeperException e) {
if (policy.equals(NodeMissingPolicy.SKIP) && e.code().equals(KeeperException.Code.NONODE))
return;
throw e;
}
}
-
+
public static void recursiveDelete(ZooKeeper zk, String zPath, NodeMissingPolicy policy) throws KeeperException, InterruptedException {
recursiveDelete(zk, zPath, -1, policy);
}
-
+
/**
* Create a persistent node with the default ACL
- *
+ *
* @return true if the node was created or altered; false if it was skipped
*/
public static boolean putPersistentData(ZooKeeper zk, String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
return putData(zk, zPath, data, CreateMode.PERSISTENT, -1, policy, PUBLIC);
}
-
+
public static boolean putPersistentData(ZooKeeper zk, String zPath, byte[] data, int version, NodeExistsPolicy policy) throws KeeperException,
InterruptedException {
return putData(zk, zPath, data, CreateMode.PERSISTENT, version, policy, PUBLIC);
}
-
+
public static boolean putPersistentData(ZooKeeper zk, String zPath, byte[] data, int version, NodeExistsPolicy policy, List<ACL> acls)
throws KeeperException, InterruptedException {
return putData(zk, zPath, data, CreateMode.PERSISTENT, version, policy, acls);
}
-
+
private static boolean putData(ZooKeeper zk, String zPath, byte[] data, CreateMode mode, int version, NodeExistsPolicy policy, List<ACL> acls)
throws KeeperException, InterruptedException {
if (policy == null)
policy = NodeExistsPolicy.FAIL;
-
+
+ final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
zk.create(zPath, data, acls, mode);
return true;
- } catch (NodeExistsException nee) {
- switch (policy) {
- case SKIP:
- return false;
- case OVERWRITE:
- try {
- zk.setData(zPath, data, version);
- return true;
- } catch (NoNodeException nne) {
- // node delete between create call and set data, so try create call again
- continue;
- }
- default:
- throw nee;
+ } catch (KeeperException e) {
+ final Code code = e.code();
+ if (code == Code.NODEEXISTS) {
+ switch (policy) {
+ case SKIP:
+ return false;
+ case OVERWRITE:
+ // overwrite the data in the node when it already exists
+ try {
+ zk.setData(zPath, data, version);
+ return true;
+ } catch (KeeperException e2) {
+ final Code code2 = e2.code();
+ if (code2 == Code.NONODE) {
+ // node delete between create call and set data, so try create call again
+ continue;
+ } else if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ // unhandled exception on setData()
+ throw e;
+ }
+ }
+ default:
+ throw e;
+ }
+ } else if (code == Code.CONNECTIONLOSS || code == Code.OPERATIONTIMEOUT || code == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ // unhandled exception on create()
+ throw e;
}
}
+
+ // Catch all to wait before retrying
+ retry.waitForNextAttempt();
}
}
-
+
public static byte[] getData(ZooKeeper zk, String zPath, Stat stat) throws KeeperException, InterruptedException {
- return zk.getData(zPath, false, stat);
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ return zk.getData(zPath, false, stat);
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
-
+
public static Stat getStatus(ZooKeeper zk, String zPath) throws KeeperException, InterruptedException {
- return zk.exists(zPath, false);
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ return zk.exists(zPath, false);
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
-
+
public static boolean exists(ZooKeeper zk, String zPath) throws KeeperException, InterruptedException {
return getStatus(zk, zPath) != null;
}
-
+
public static void recursiveCopyPersistent(ZooKeeper zk, String source, String destination, NodeExistsPolicy policy) throws KeeperException,
InterruptedException {
Stat stat = null;
@@ -192,9 +304,10 @@ public class ZooUtil {
throw KeeperException.create(Code.NODEEXISTS, source);
}
}
-
+
stat = new Stat();
- byte[] data = zk.getData(source, false, stat);
+ byte[] data = getData(zk, source, stat);
+
if (stat.getEphemeralOwner() == 0) {
if (data == null)
throw KeeperException.create(Code.NONODE, source);
@@ -204,61 +317,113 @@ public class ZooUtil {
recursiveCopyPersistent(zk, source + "/" + child, destination + "/" + child, policy);
}
}
-
+
public static boolean putPrivatePersistentData(ZooKeeper zk, String zPath, byte[] data, NodeExistsPolicy policy) throws KeeperException, InterruptedException {
return putData(zk, zPath, data, CreateMode.PERSISTENT, -1, policy, PRIVATE);
}
-
+
public static String putPersistentSequential(ZooKeeper zk, String zPath, byte[] data) throws KeeperException, InterruptedException {
- return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.PERSISTENT_SEQUENTIAL);
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.PERSISTENT_SEQUENTIAL);
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
-
+
public static String putEphemeralData(ZooKeeper zk, String zPath, byte[] data) throws KeeperException, InterruptedException {
- return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL);
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL);
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
public static String putEphemeralSequential(ZooKeeper zk, String zPath, byte[] data) throws KeeperException, InterruptedException {
- return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL_SEQUENTIAL);
+ final Retry retry = RETRY_FACTORY.create();
+ while (true) {
+ try {
+ return zk.create(zPath, data, ZooUtil.PUBLIC, CreateMode.EPHEMERAL_SEQUENTIAL);
+ } catch (KeeperException e) {
+ final Code c = e.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, e);
+ } else {
+ throw e;
+ }
+ }
+
+ retry.waitForNextAttempt();
+ }
}
-
+
public static byte[] getLockData(ZooCache zc, String path) {
-
+
List<String> children = zc.getChildren(path);
-
+
if (children == null || children.size() == 0) {
return null;
}
-
+
children = new ArrayList<String>(children);
Collections.sort(children);
-
+
String lockNode = children.get(0);
-
+
return zc.get(path + "/" + lockNode);
}
-
+
public static boolean isLockHeld(ZooKeeper zk, LockID lid) throws KeeperException, InterruptedException {
-
+ final Retry retry = RETRY_FACTORY.create();
while (true) {
try {
+ // TODO push down retry to getChildren and exists
List<String> children = zk.getChildren(lid.path, false);
-
+
if (children.size() == 0) {
return false;
}
-
+
Collections.sort(children);
-
+
String lockNode = children.get(0);
if (!lid.node.equals(lockNode))
return false;
-
+
Stat stat = zk.exists(lid.path + "/" + lid.node, false);
return stat != null && stat.getEphemeralOwner() == lid.eid;
- } catch (KeeperException.ConnectionLossException ex) {
- UtilWaitThread.sleep(1000);
+ } catch (KeeperException ex) {
+ final Code c = ex.code();
+ if (c == Code.CONNECTIONLOSS || c == Code.OPERATIONTIMEOUT || c == Code.SESSIONEXPIRED) {
+ // TODO ZooKeeper needs to be recreated with SESSIONEXPIRED, should use ZooSession
+ retryOrThrow(retry, ex);
+ }
}
+
+ retry.waitForNextAttempt();
}
}
-
+
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandlerTest.java
----------------------------------------------------------------------
diff --git a/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandlerTest.java b/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandlerTest.java
deleted file mode 100644
index 0613a1f..0000000
--- a/fate/src/test/java/org/apache/accumulo/fate/zookeeper/RetryingInvocationHandlerTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.accumulo.fate.zookeeper;
-
-import java.lang.reflect.Method;
-import org.apache.zookeeper.KeeperException.ConnectionLossException;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-import static org.easymock.EasyMock.aryEq;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
-
-public class RetryingInvocationHandlerTest {
- private static final String PATH = "/path/to/somewhere";
- private static final byte[] DATA = {(byte) 1, (byte) 2};
- private static final Object[] ARGS = {PATH, DATA};
- private static final String RV = "OK";
-
- private static Method putMethod;
-
- @BeforeClass
- public static void setUpClass() throws Exception {
- putMethod = IZooReaderWriter.class.getMethod("putEphemeralData", String.class, byte[].class);
- }
-
- private IZooReaderWriter zrw;
- private RetryingInvocationHandler ih;
-
- @Before
- public void setUp() throws Exception {
- zrw = createMock(IZooReaderWriter.class);
- ih = new RetryingInvocationHandler(zrw);
- }
-
- @Test
- public void testInvokeSuccessful() throws Throwable {
- expect(zrw.putEphemeralData(eq(PATH), aryEq(DATA))).andReturn(RV);
- replay(zrw);
- Object rv = ih.invoke(null, putMethod, ARGS);
- verify(zrw);
- assertEquals(RV, rv);
- }
-
- @Test
- public void testInvokeRetrySuccessful() throws Throwable {
- ConnectionLossException e = createMock(ConnectionLossException.class);
- expect(zrw.putEphemeralData(eq(PATH), aryEq(DATA))).andThrow(e);
- expect(zrw.putEphemeralData(eq(PATH), aryEq(DATA))).andThrow(e);
- expect(zrw.putEphemeralData(eq(PATH), aryEq(DATA))).andReturn(RV);
- replay(zrw);
- Object rv = ih.invoke(null, putMethod, ARGS);
- verify(zrw);
- assertEquals(RV, rv);
- }
-
- @Test(expected = InterruptedException.class)
- public void testInvokeRetryFailure() throws Throwable {
- ConnectionLossException e = createMock(ConnectionLossException.class);
- expect(zrw.putEphemeralData(eq(PATH), aryEq(DATA))).andThrow(e);
- expect(zrw.putEphemeralData(eq(PATH), aryEq(DATA))).andThrow(new InterruptedException());
- replay(zrw);
- try {
- ih.invoke(null, putMethod, ARGS);
- } finally {
- verify(zrw);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/Accumulo.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/Accumulo.java b/server/base/src/main/java/org/apache/accumulo/server/Accumulo.java
index ca70efe..6ba05cc 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/Accumulo.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/Accumulo.java
@@ -301,7 +301,7 @@ public class Accumulo {
public static void abortIfFateTransactions() {
try {
final ReadOnlyTStore<Accumulo> fate = new ReadOnlyStore<Accumulo>(new ZooStore<Accumulo>(ZooUtil.getRoot(HdfsZooInstance.getInstance()) + Constants.ZFATE,
- ZooReaderWriter.getRetryingInstance()));
+ ZooReaderWriter.getInstance()));
if (!(fate.list().isEmpty())) {
throw new AccumuloException("Aborting upgrade because there are outstanding FATE transactions from a previous Accumulo version. Please see the README document for instructions on what to do under your previous version.");
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java b/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
index 63bd894..e8d5bbf 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/master/LiveTServerSet.java
@@ -388,7 +388,7 @@ public class LiveTServerSet implements Watcher {
log.info("Removing zookeeper lock for " + server);
String fullpath = ZooUtil.getRoot(instance) + Constants.ZTSERVERS + "/" + zPath;
try {
- ZooReaderWriter.getRetryingInstance().recursiveDelete(fullpath, SKIP);
+ ZooReaderWriter.getInstance().recursiveDelete(fullpath, SKIP);
} catch (Exception e) {
String msg = "error removing tablet server lock";
log.fatal(msg, e);
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
index 1646a28..5f6ff71 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthenticator.java
@@ -39,40 +39,40 @@ import org.apache.zookeeper.KeeperException;
public final class ZKAuthenticator implements Authenticator {
static final Logger log = Logger.getLogger(ZKAuthenticator.class);
private static Authenticator zkAuthenticatorInstance = null;
-
+
private String ZKUserPath;
private final ZooCache zooCache;
-
+
public static synchronized Authenticator getInstance() {
if (zkAuthenticatorInstance == null)
zkAuthenticatorInstance = new ZKAuthenticator();
return zkAuthenticatorInstance;
}
-
+
public ZKAuthenticator() {
zooCache = new ZooCache();
}
-
+
@Override
public void initialize(String instanceId, boolean initialize) {
ZKUserPath = Constants.ZROOT + "/" + instanceId + "/users";
}
-
+
@Override
public void initializeSecurity(TCredentials credentials, String principal, byte[] token) throws AccumuloSecurityException {
try {
// remove old settings from zookeeper first, if any
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
synchronized (zooCache) {
zooCache.clear();
if (zoo.exists(ZKUserPath)) {
zoo.recursiveDelete(ZKUserPath, NodeMissingPolicy.SKIP);
log.info("Removed " + ZKUserPath + "/" + " from zookeeper");
}
-
+
// prep parent node of users with root username
zoo.putPersistentData(ZKUserPath, principal.getBytes(Constants.UTF8), NodeExistsPolicy.FAIL);
-
+
constructUser(principal, ZKSecurityTool.createPass(token));
}
} catch (KeeperException e) {
@@ -86,23 +86,23 @@ public final class ZKAuthenticator implements Authenticator {
throw new RuntimeException(e);
}
}
-
+
/**
* Sets up the user in ZK for the provided user. No checking for existence is done here, it should be done before calling.
*/
private void constructUser(String user, byte[] pass) throws KeeperException, InterruptedException {
synchronized (zooCache) {
zooCache.clear();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.putPrivatePersistentData(ZKUserPath + "/" + user, pass, NodeExistsPolicy.FAIL);
}
}
-
+
@Override
public Set<String> listUsers() {
return new TreeSet<String>(zooCache.getChildren(ZKUserPath));
}
-
+
/**
* Creates a user with no permissions whatsoever
*/
@@ -125,13 +125,13 @@ public final class ZKAuthenticator implements Authenticator {
throw new AccumuloSecurityException(principal, SecurityErrorCode.DEFAULT_SECURITY_ERROR, e);
}
}
-
+
@Override
public void dropUser(String user) throws AccumuloSecurityException {
try {
synchronized (zooCache) {
zooCache.clear();
- ZooReaderWriter.getRetryingInstance().recursiveDelete(ZKUserPath + "/" + user, NodeMissingPolicy.FAIL);
+ ZooReaderWriter.getInstance().recursiveDelete(ZKUserPath + "/" + user, NodeMissingPolicy.FAIL);
}
} catch (InterruptedException e) {
log.error(e, e);
@@ -143,7 +143,7 @@ public final class ZKAuthenticator implements Authenticator {
throw new AccumuloSecurityException(user, SecurityErrorCode.CONNECTION_ERROR, e);
}
}
-
+
@Override
public void changePassword(String principal, AuthenticationToken token) throws AccumuloSecurityException {
if (!(token instanceof PasswordToken))
@@ -153,7 +153,7 @@ public final class ZKAuthenticator implements Authenticator {
try {
synchronized (zooCache) {
zooCache.clear(ZKUserPath + "/" + principal);
- ZooReaderWriter.getRetryingInstance().putPrivatePersistentData(ZKUserPath + "/" + principal, ZKSecurityTool.createPass(pt.getPassword()),
+ ZooReaderWriter.getInstance().putPrivatePersistentData(ZKUserPath + "/" + principal, ZKSecurityTool.createPass(pt.getPassword()),
NodeExistsPolicy.OVERWRITE);
}
} catch (KeeperException e) {
@@ -169,7 +169,7 @@ public final class ZKAuthenticator implements Authenticator {
} else
throw new AccumuloSecurityException(principal, SecurityErrorCode.USER_DOESNT_EXIST); // user doesn't exist
}
-
+
/**
* Checks if a user exists
*/
@@ -177,12 +177,12 @@ public final class ZKAuthenticator implements Authenticator {
public boolean userExists(String user) {
return zooCache.get(ZKUserPath + "/" + user) != null;
}
-
+
@Override
public boolean validSecurityHandlers(Authorizor auth, PermissionHandler pm) {
return true;
}
-
+
@Override
public boolean authenticateUser(String principal, AuthenticationToken token) throws AccumuloSecurityException {
if (!(token instanceof PasswordToken))
@@ -199,14 +199,14 @@ public final class ZKAuthenticator implements Authenticator {
}
return result;
}
-
+
@Override
public Set<Class<? extends AuthenticationToken>> getSupportedTokenTypes() {
Set<Class<? extends AuthenticationToken>> cs = new HashSet<Class<? extends AuthenticationToken>>();
cs.add(PasswordToken.class);
return cs;
}
-
+
@Override
public boolean validTokenClass(String tokenClass) {
return tokenClass.equals(PasswordToken.class.getName());
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
index bbaf592..75b73fc 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKAuthorizor.java
@@ -81,7 +81,7 @@ public class ZKAuthorizor implements Authorizor {
@Override
public void initializeSecurity(TCredentials itw, String rootuser) throws AccumuloSecurityException {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
// create the root user with all system privileges, no table privileges, and no record-level authorizations
Set<SystemPermission> rootPerms = new TreeSet<SystemPermission>();
@@ -110,7 +110,7 @@ public class ZKAuthorizor implements Authorizor {
@Override
public void initUser(String user) throws AccumuloSecurityException {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
try {
zoo.putPersistentData(ZKUserPath + "/" + user, new byte[0], NodeExistsPolicy.SKIP);
} catch (KeeperException e) {
@@ -126,7 +126,7 @@ public class ZKAuthorizor implements Authorizor {
public void dropUser(String user) throws AccumuloSecurityException {
try {
synchronized (zooCache) {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserAuths, NodeMissingPolicy.SKIP);
zooCache.clear(ZKUserPath + "/" + user);
}
@@ -147,7 +147,7 @@ public class ZKAuthorizor implements Authorizor {
try {
synchronized (zooCache) {
zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserAuths, ZKSecurityTool.convertAuthorizations(authorizations),
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserAuths, ZKSecurityTool.convertAuthorizations(authorizations),
NodeExistsPolicy.OVERWRITE);
}
} catch (KeeperException e) {
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
index 1b7e7d3..3cac2e9 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/security/handler/ZKPermHandler.java
@@ -81,14 +81,14 @@ public class ZKPermHandler implements PermissionHandler {
byte[] serializedPerms;
try {
String path = ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table;
- ZooReaderWriter.getRetryingInstance().sync(path);
- serializedPerms = ZooReaderWriter.getRetryingInstance().getData(path, null);
+ ZooReaderWriter.getInstance().sync(path);
+ serializedPerms = ZooReaderWriter.getInstance().getData(path, null);
} catch (KeeperException e) {
if (e.code() == Code.NONODE) {
// maybe the table was just deleted?
try {
// check for existence:
- ZooReaderWriter.getRetryingInstance().getData(ZKTablePath + "/" + table, null);
+ ZooReaderWriter.getInstance().getData(ZKTablePath + "/" + table, null);
// it's there, you don't have permission
return false;
} catch (InterruptedException ex) {
@@ -129,14 +129,14 @@ public class ZKPermHandler implements PermissionHandler {
byte[] serializedPerms;
try {
String path = ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace;
- ZooReaderWriter.getRetryingInstance().sync(path);
- serializedPerms = ZooReaderWriter.getRetryingInstance().getData(path, null);
+ ZooReaderWriter.getInstance().sync(path);
+ serializedPerms = ZooReaderWriter.getInstance().getData(path, null);
} catch (KeeperException e) {
if (e.code() == Code.NONODE) {
// maybe the namespace was just deleted?
try {
// check for existence:
- ZooReaderWriter.getRetryingInstance().getData(ZKNamespacePath + "/" + namespace, null);
+ ZooReaderWriter.getInstance().getData(ZKNamespacePath + "/" + namespace, null);
// it's there, you don't have permission
return false;
} catch (InterruptedException ex) {
@@ -187,7 +187,7 @@ public class ZKPermHandler implements PermissionHandler {
if (perms.add(permission)) {
synchronized (zooCache) {
zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(perms),
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(perms),
NodeExistsPolicy.OVERWRITE);
}
}
@@ -213,7 +213,7 @@ public class ZKPermHandler implements PermissionHandler {
if (tablePerms.add(permission)) {
synchronized (zooCache) {
zooCache.clear(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table);
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, ZKSecurityTool.convertTablePermissions(tablePerms),
NodeExistsPolicy.OVERWRITE);
}
@@ -240,7 +240,7 @@ public class ZKPermHandler implements PermissionHandler {
if (namespacePerms.add(permission)) {
synchronized (zooCache) {
zooCache.clear(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace);
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace, ZKSecurityTool.convertNamespacePermissions(namespacePerms),
NodeExistsPolicy.OVERWRITE);
}
@@ -268,7 +268,7 @@ public class ZKPermHandler implements PermissionHandler {
if (sysPerms.remove(permission)) {
synchronized (zooCache) {
zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(sysPerms),
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserSysPerms, ZKSecurityTool.convertSystemPermissions(sysPerms),
NodeExistsPolicy.OVERWRITE);
}
}
@@ -293,7 +293,7 @@ public class ZKPermHandler implements PermissionHandler {
try {
if (tablePerms.remove(permission)) {
zooCache.clear();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
if (tablePerms.size() == 0)
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, NodeMissingPolicy.SKIP);
else
@@ -321,7 +321,7 @@ public class ZKPermHandler implements PermissionHandler {
try {
if (namespacePerms.remove(permission)) {
zooCache.clear();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
if (namespacePerms.size() == 0)
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace, NodeMissingPolicy.SKIP);
else
@@ -342,7 +342,7 @@ public class ZKPermHandler implements PermissionHandler {
try {
synchronized (zooCache) {
zooCache.clear();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
for (String user : zooCache.getChildren(ZKUserPath))
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table, NodeMissingPolicy.SKIP);
}
@@ -360,7 +360,7 @@ public class ZKPermHandler implements PermissionHandler {
try {
synchronized (zooCache) {
zooCache.clear();
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
for (String user : zooCache.getChildren(ZKUserPath))
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace, NodeMissingPolicy.SKIP);
}
@@ -375,7 +375,7 @@ public class ZKPermHandler implements PermissionHandler {
@Override
public void initializeSecurity(TCredentials itw, String rootuser) throws AccumuloSecurityException {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
// create the root user with all system privileges, no table privileges, and no record-level authorizations
Set<SystemPermission> rootPerms = new TreeSet<SystemPermission>();
@@ -412,7 +412,7 @@ public class ZKPermHandler implements PermissionHandler {
@Override
public void initUser(String user) throws AccumuloSecurityException {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
try {
zoo.putPersistentData(ZKUserPath + "/" + user, new byte[0], NodeExistsPolicy.SKIP);
zoo.putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms, new byte[0], NodeExistsPolicy.SKIP);
@@ -432,7 +432,7 @@ public class ZKPermHandler implements PermissionHandler {
private void createTablePerm(String user, String table, Set<TablePermission> perms) throws KeeperException, InterruptedException {
synchronized (zooCache) {
zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table,
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserTablePerms + "/" + table,
ZKSecurityTool.convertTablePermissions(perms), NodeExistsPolicy.FAIL);
}
}
@@ -443,7 +443,7 @@ public class ZKPermHandler implements PermissionHandler {
private void createNamespacePerm(String user, String namespace, Set<NamespacePermission> perms) throws KeeperException, InterruptedException {
synchronized (zooCache) {
zooCache.clear();
- ZooReaderWriter.getRetryingInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace,
+ ZooReaderWriter.getInstance().putPersistentData(ZKUserPath + "/" + user + ZKUserNamespacePerms + "/" + namespace,
ZKSecurityTool.convertNamespacePermissions(perms), NodeExistsPolicy.FAIL);
}
}
@@ -452,7 +452,7 @@ public class ZKPermHandler implements PermissionHandler {
public void cleanUser(String user) throws AccumuloSecurityException {
try {
synchronized (zooCache) {
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserSysPerms, NodeMissingPolicy.SKIP);
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserTablePerms, NodeMissingPolicy.SKIP);
zoo.recursiveDelete(ZKUserPath + "/" + user + ZKUserNamespacePerms, NodeMissingPolicy.SKIP);
@@ -475,8 +475,8 @@ public class ZKPermHandler implements PermissionHandler {
byte[] perms;
try {
String path = ZKUserPath + "/" + user + ZKUserSysPerms;
- ZooReaderWriter.getRetryingInstance().sync(path);
- perms = ZooReaderWriter.getRetryingInstance().getData(path, null);
+ ZooReaderWriter.getInstance().sync(path);
+ perms = ZooReaderWriter.getInstance().getData(path, null);
} catch (KeeperException e) {
if (e.code() == Code.NONODE) {
return false;
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java b/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
index 7a61eb6..71b7155 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/tables/TableManager.java
@@ -63,7 +63,7 @@ public class TableManager {
log.debug("Creating ZooKeeper entries for new namespace " + namespace + " (ID: " + namespaceId + ")");
String zPath = Constants.ZROOT + "/" + instanceId + Constants.ZNAMESPACES + "/" + namespaceId;
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.putPersistentData(zPath, new byte[0], existsPolicy);
zoo.putPersistentData(zPath + Constants.ZNAMESPACE_NAME, namespace.getBytes(Constants.UTF8), existsPolicy);
zoo.putPersistentData(zPath + Constants.ZNAMESPACE_CONF, new byte[0], existsPolicy);
@@ -76,7 +76,7 @@ public class TableManager {
Pair<String,String> qualifiedTableName = Tables.qualify(tableName);
tableName = qualifiedTableName.getSecond();
String zTablePath = Constants.ZROOT + "/" + instanceId + Constants.ZTABLES + "/" + tableId;
- IZooReaderWriter zoo = ZooReaderWriter.getRetryingInstance();
+ IZooReaderWriter zoo = ZooReaderWriter.getInstance();
zoo.putPersistentData(zTablePath, new byte[0], existsPolicy);
zoo.putPersistentData(zTablePath + Constants.ZTABLE_CONF, new byte[0], existsPolicy);
zoo.putPersistentData(zTablePath + Constants.ZTABLE_NAMESPACE, namespaceId.getBytes(Constants.UTF8), existsPolicy);
@@ -132,7 +132,7 @@ public class TableManager {
String statePath = ZooUtil.getRoot(HdfsZooInstance.getInstance()) + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_STATE;
try {
- ZooReaderWriter.getRetryingInstance().mutate(statePath, newState.name().getBytes(Constants.UTF8), ZooUtil.PUBLIC, new Mutator() {
+ ZooReaderWriter.getInstance().mutate(statePath, newState.name().getBytes(Constants.UTF8), ZooUtil.PUBLIC, new Mutator() {
@Override
public byte[] mutate(byte[] oldData) throws Exception {
TableState oldState = TableState.UNKNOWN;
@@ -205,13 +205,13 @@ public class TableManager {
String srcTablePath = Constants.ZROOT + "/" + instance.getInstanceID() + Constants.ZTABLES + "/" + srcTable + Constants.ZTABLE_CONF;
String newTablePath = Constants.ZROOT + "/" + instance.getInstanceID() + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_CONF;
- ZooReaderWriter.getRetryingInstance().recursiveCopyPersistent(srcTablePath, newTablePath, NodeExistsPolicy.OVERWRITE);
+ ZooReaderWriter.getInstance().recursiveCopyPersistent(srcTablePath, newTablePath, NodeExistsPolicy.OVERWRITE);
for (Entry<String,String> entry : propertiesToSet.entrySet())
TablePropUtil.setTableProperty(tableId, entry.getKey(), entry.getValue());
for (String prop : propertiesToExclude)
- ZooReaderWriter.getRetryingInstance().recursiveDelete(
+ ZooReaderWriter.getInstance().recursiveDelete(
Constants.ZROOT + "/" + instance.getInstanceID() + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_CONF + "/" + prop, NodeMissingPolicy.SKIP);
updateTableStateCache(tableId);
@@ -220,9 +220,9 @@ public class TableManager {
public void removeTable(String tableId) throws KeeperException, InterruptedException {
synchronized (tableStateCache) {
tableStateCache.remove(tableId);
- ZooReaderWriter.getRetryingInstance().recursiveDelete(ZooUtil.getRoot(instance) + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_STATE,
+ ZooReaderWriter.getInstance().recursiveDelete(ZooUtil.getRoot(instance) + Constants.ZTABLES + "/" + tableId + Constants.ZTABLE_STATE,
NodeMissingPolicy.SKIP);
- ZooReaderWriter.getRetryingInstance().recursiveDelete(ZooUtil.getRoot(instance) + Constants.ZTABLES + "/" + tableId, NodeMissingPolicy.SKIP);
+ ZooReaderWriter.getInstance().recursiveDelete(ZooUtil.getRoot(instance) + Constants.ZTABLES + "/" + tableId, NodeMissingPolicy.SKIP);
}
}
@@ -312,7 +312,7 @@ public class TableManager {
}
public void removeNamespace(String namespaceId) throws KeeperException, InterruptedException {
- ZooReaderWriter.getRetryingInstance().recursiveDelete(ZooUtil.getRoot(instance) + Constants.ZNAMESPACES + "/" + namespaceId, NodeMissingPolicy.SKIP);
+ ZooReaderWriter.getInstance().recursiveDelete(ZooUtil.getRoot(instance) + Constants.ZNAMESPACES + "/" + namespaceId, NodeMissingPolicy.SKIP);
}
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java b/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java
index 4ae8335..eabdc0d 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/tablets/UniqueNameAllocator.java
@@ -48,7 +48,7 @@ public class UniqueNameAllocator {
final int allocate = 100 + rand.nextInt(100);
try {
- byte[] max = ZooReaderWriter.getRetryingInstance().mutate(nextNamePath, null, ZooUtil.PRIVATE, new ZooReaderWriter.Mutator() {
+ byte[] max = ZooReaderWriter.getInstance().mutate(nextNamePath, null, ZooUtil.PRIVATE, new ZooReaderWriter.Mutator() {
public byte[] mutate(byte[] currentValue) throws Exception {
long l = Long.parseLong(new String(currentValue, Constants.UTF8), Character.MAX_RADIX);
l += allocate;
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java
index f7c1e68..b02e5d4 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooQueueLock.java
@@ -24,11 +24,11 @@ import org.apache.accumulo.fate.zookeeper.DistributedReadWriteLock;
import org.apache.zookeeper.KeeperException;
public class ZooQueueLock extends org.apache.accumulo.fate.zookeeper.ZooQueueLock {
-
+
public ZooQueueLock(String path, boolean ephemeral) throws KeeperException, InterruptedException {
- super(ZooReaderWriter.getRetryingInstance(), path, ephemeral);
+ super(ZooReaderWriter.getInstance(), path, ephemeral);
}
-
+
public static void main(String args[]) throws InterruptedException, KeeperException {
ZooQueueLock lock = new ZooQueueLock("/lock", true);
DistributedReadWriteLock rlocker = new DistributedReadWriteLock(lock, "reader".getBytes(Constants.UTF8));
@@ -50,5 +50,5 @@ public class ZooQueueLock extends org.apache.accumulo.fate.zookeeper.ZooQueueLoc
readLock.lock();
System.out.println("success");
}
-
+
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
index f950077..435591d 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriter.java
@@ -16,25 +16,15 @@
*/
package org.apache.accumulo.server.zookeeper;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
import org.apache.accumulo.core.Constants;
import org.apache.accumulo.core.conf.AccumuloConfiguration;
import org.apache.accumulo.core.conf.Property;
-import org.apache.accumulo.fate.util.UtilWaitThread;
-import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
import org.apache.accumulo.server.conf.ServerConfiguration;
-import org.apache.log4j.Logger;
-import org.apache.zookeeper.KeeperException;
public class ZooReaderWriter extends org.apache.accumulo.fate.zookeeper.ZooReaderWriter {
private static final String SCHEME = "digest";
private static final String USER = "accumulo";
private static ZooReaderWriter instance = null;
- private static IZooReaderWriter retryingInstance = null;
public ZooReaderWriter(String string, int timeInMillis, String secret) {
super(string, timeInMillis, SCHEME, (USER + ":" + secret).getBytes(Constants.UTF8));
@@ -49,39 +39,4 @@ public class ZooReaderWriter extends org.apache.accumulo.fate.zookeeper.ZooReade
return instance;
}
- /**
- * get an instance that retries when zookeeper connection errors occur
- *
- * @return an instance that retries when Zookeeper connection errors occur.
- */
- public static synchronized IZooReaderWriter getRetryingInstance() {
-
- if (retryingInstance == null) {
- final IZooReaderWriter inst = getInstance();
-
- InvocationHandler ih = new InvocationHandler() {
- @Override
- public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
- long retryTime = 250;
- while (true) {
- try {
- return method.invoke(inst, args);
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof KeeperException.ConnectionLossException) {
- Logger.getLogger(ZooReaderWriter.class).warn("Error connecting to zookeeper, will retry in " + retryTime, e.getCause());
- UtilWaitThread.sleep(retryTime);
- retryTime = Math.min(5000, retryTime + 250);
- } else {
- throw e.getCause();
- }
- }
- }
- }
- };
-
- retryingInstance = (IZooReaderWriter) Proxy.newProxyInstance(ZooReaderWriter.class.getClassLoader(), new Class[] {IZooReaderWriter.class}, ih);
- }
-
- return retryingInstance;
- }
}
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c023f74e/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
index 0a9508c..4a7111d 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/zookeeper/ZooReaderWriterFactory.java
@@ -16,14 +16,10 @@
*/
package org.apache.accumulo.server.zookeeper;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Proxy;
-
import org.apache.accumulo.core.Constants;
import org.apache.accumulo.core.conf.AccumuloConfiguration;
import org.apache.accumulo.core.conf.Property;
import org.apache.accumulo.fate.zookeeper.IZooReaderWriter;
-import org.apache.accumulo.fate.zookeeper.RetryingInvocationHandler;
import org.apache.accumulo.fate.zookeeper.ZooReaderWriter;
import org.apache.accumulo.server.conf.ServerConfiguration;
@@ -34,7 +30,6 @@ public class ZooReaderWriterFactory {
private static final String SCHEME = "digest";
private static final String USER = "accumulo";
private static IZooReaderWriter instance = null;
- private static IZooReaderWriter retryingInstance = null;
/**
* Gets a new reader/writer.
@@ -66,21 +61,4 @@ public class ZooReaderWriterFactory {
return instance;
}
}
-
- /**
- * Gets a reader/writer, retrieving ZooKeeper information from the site configuration, and that retries on connection loss. The same instance may be returned
- * for multiple calls.
- *
- * @return retrying reader/writer
- */
- public IZooReaderWriter getRetryingInstance() {
- synchronized (ZooReaderWriterFactory.class) {
- if (retryingInstance == null) {
- IZooReaderWriter inst = getInstance();
- InvocationHandler ih = new RetryingInvocationHandler(inst);
- retryingInstance = (IZooReaderWriter) Proxy.newProxyInstance(IZooReaderWriter.class.getClassLoader(), new Class[] {IZooReaderWriter.class}, ih);
- }
- return retryingInstance;
- }
- }
}