You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by iv...@apache.org on 2012/12/03 17:59:06 UTC
svn commit: r1416590 - in /zookeeper/bookkeeper/trunk: ./
bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/
bookkeeper-server/src/main/java/org/apache/bookkeeper/client/
bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/ bookkeepe...
Author: ivank
Date: Mon Dec 3 16:59:04 2012
New Revision: 1416590
URL: http://svn.apache.org/viewvc?rev=1416590&view=rev
Log:
BOOKKEEPER-347: Provide mechanism to detect r-o bookie by the bookie clients (Vinay via ivank)
Modified:
zookeeper/bookkeeper/trunk/CHANGES.txt
zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BKException.java
zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperAdmin.java
zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookieWatcher.java
zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java
zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ReadOnlyBookieTest.java
Modified: zookeeper/bookkeeper/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/CHANGES.txt?rev=1416590&r1=1416589&r2=1416590&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/CHANGES.txt (original)
+++ zookeeper/bookkeeper/trunk/CHANGES.txt Mon Dec 3 16:59:04 2012
@@ -118,6 +118,8 @@ Trunk (unreleased changes)
BOOKKEEPER-459: Rename metastore mock implementation to InMemory implementation (jiannan via ivank)
+ BOOKKEEPER-347: Provide mechanism to detect r-o bookie by the bookie clients (Vinay via ivank)
+
hedwig-protocol:
BOOKKEEPER-394: CompositeException message is not useful (Stu Hood via sijie)
Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java?rev=1416590&r1=1416589&r2=1416590&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java Mon Dec 3 16:59:04 2012
@@ -65,6 +65,8 @@ import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.Watcher.Event.EventType;
+import com.google.common.annotations.VisibleForTesting;
+
/**
* Implements a bookie.
*
@@ -657,7 +659,8 @@ public class Bookie extends Thread {
/*
* Transition the bookie to readOnly mode
*/
- void transitionToReadOnlyMode() {
+ @VisibleForTesting
+ public void transitionToReadOnlyMode() {
if (!readOnly.compareAndSet(false, true)) {
return;
}
@@ -682,11 +685,11 @@ public class Bookie extends Thread {
// this node is just now created by someone.
}
}
+ // Create the readonly node
+ zk.create(this.bookieRegistrationPath + READONLY + "/" + getMyId(), new byte[0], Ids.OPEN_ACL_UNSAFE,
+ CreateMode.EPHEMERAL);
// Clear the current registered node
zk.delete(zkBookieRegPath, -1);
- // Create the readonly node
- zk.create(this.bookieRegistrationPath + READONLY + "/" + getMyId(),
- new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
} catch (IOException e) {
LOG.error("Error in transition to ReadOnly Mode."
+ " Shutting down", e);
Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BKException.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BKException.java?rev=1416590&r1=1416589&r2=1416590&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BKException.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BKException.java Mon Dec 3 16:59:04 2012
@@ -84,6 +84,8 @@ public abstract class BKException extend
return new BKUnauthorizedAccessException();
case Code.UnclosedFragmentException:
return new BKUnclosedFragmentException();
+ case Code.WriteOnReadOnlyBookieException:
+ return new BKWriteOnReadOnlyBookieException();
default:
return new BKIllegalOpException();
}
@@ -117,6 +119,7 @@ public abstract class BKException extend
int LedgerFencedException = -101;
int UnauthorizedAccessException = -102;
int UnclosedFragmentException = -103;
+ int WriteOnReadOnlyBookieException = -104;
}
public void setCode(int code) {
@@ -171,6 +174,8 @@ public abstract class BKException extend
return "Attempted to access ledger using the wrong password";
case Code.UnclosedFragmentException:
return "Attempting to use an unclosed fragment; This is not safe";
+ case Code.WriteOnReadOnlyBookieException:
+ return "Attempting to write on ReadOnly bookie";
default:
return "Invalid operation";
}
@@ -301,4 +306,10 @@ public abstract class BKException extend
super(Code.UnclosedFragmentException);
}
}
+
+ public static class BKWriteOnReadOnlyBookieException extends BKException {
+ public BKWriteOnReadOnlyBookieException() {
+ super(Code.WriteOnReadOnlyBookieException);
+ }
+ }
}
Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperAdmin.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperAdmin.java?rev=1416590&r1=1416589&r2=1416590&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperAdmin.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperAdmin.java Mon Dec 3 16:59:04 2012
@@ -373,6 +373,10 @@ public class BookKeeperAdmin {
return;
}
for (String bookieNode : children) {
+ if (Bookie.READONLY.equals(bookieNode)) {
+ // exclude the readonly node from available bookies.
+ continue;
+ }
String parts[] = bookieNode.split(COLON);
if (parts.length < 2) {
LOG.error("Bookie Node retrieved from ZK has invalid name format: " + bookieNode);
Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookieWatcher.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookieWatcher.java?rev=1416590&r1=1416589&r2=1416590&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookieWatcher.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookieWatcher.java Mon Dec 3 16:59:04 2012
@@ -29,17 +29,22 @@ import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
+
+import org.apache.bookkeeper.bookie.Bookie;
import org.apache.bookkeeper.client.BKException.BKNotEnoughBookiesException;
import org.apache.bookkeeper.conf.ClientConfiguration;
import org.apache.bookkeeper.util.SafeRunnable;
import org.apache.bookkeeper.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.AsyncCallback.ChildrenCallback;
import org.apache.zookeeper.KeeperException.Code;
+import org.apache.zookeeper.KeeperException.NodeExistsException;
+import org.apache.zookeeper.ZooDefs.Ids;
/**
* This class is responsible for maintaining a consistent view of what bookies
@@ -67,12 +72,14 @@ class BookieWatcher implements Watcher,
readBookies();
}
};
+ private ReadOnlyBookieWatcher readOnlyBookieWatcher;
- public BookieWatcher(ClientConfiguration conf, BookKeeper bk) {
+ public BookieWatcher(ClientConfiguration conf, BookKeeper bk) throws KeeperException, InterruptedException {
this.bk = bk;
// ZK bookie registration path
this.bookieRegistrationPath = conf.getZkAvailableBookiesPath();
this.scheduler = Executors.newSingleThreadScheduledExecutor();
+ readOnlyBookieWatcher = new ReadOnlyBookieWatcher(conf, bk);
}
public void halt() {
@@ -102,6 +109,27 @@ class BookieWatcher implements Watcher,
return;
}
+ // Just exclude the 'readonly' znode to exclude r-o bookies from
+ // available nodes list.
+ children.remove(Bookie.READONLY);
+
+ HashSet<InetSocketAddress> newBookieAddrs = convertToBookieAddresses(children);
+
+ final HashSet<InetSocketAddress> deadBookies;
+ synchronized (this) {
+ deadBookies = (HashSet<InetSocketAddress>)knownBookies.clone();
+ deadBookies.removeAll(newBookieAddrs);
+ // No need to close readonly bookie clients.
+ deadBookies.removeAll(readOnlyBookieWatcher.getReadOnlyBookies());
+ knownBookies = newBookieAddrs;
+ }
+
+ if (bk.getBookieClient() != null) {
+ bk.getBookieClient().closeClients(deadBookies);
+ }
+ }
+
+ private static HashSet<InetSocketAddress> convertToBookieAddresses(List<String> children) {
// Read the bookie addresses into a set for efficient lookup
HashSet<InetSocketAddress> newBookieAddrs = new HashSet<InetSocketAddress>();
for (String bookieAddrString : children) {
@@ -114,17 +142,7 @@ class BookieWatcher implements Watcher,
}
newBookieAddrs.add(bookieAddr);
}
-
- final HashSet<InetSocketAddress> deadBookies;
- synchronized (this) {
- deadBookies = (HashSet<InetSocketAddress>)knownBookies.clone();
- deadBookies.removeAll(newBookieAddrs);
- knownBookies = newBookieAddrs;
- }
-
- if (bk.getBookieClient() != null) {
- bk.getBookieClient().closeClients(deadBookies);
- }
+ return newBookieAddrs;
}
/**
@@ -133,6 +151,9 @@ class BookieWatcher implements Watcher,
* @throws KeeperException
*/
public void readBookiesBlocking() throws InterruptedException, KeeperException {
+ // Read readonly bookies first
+ readOnlyBookieWatcher.readROBookiesBlocking();
+
final LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
readBookies(new ChildrenCallback() {
public void processResult(int rc, String path, Object ctx, List<String> children) {
@@ -213,4 +234,82 @@ class BookieWatcher implements Watcher,
throw new BKNotEnoughBookiesException();
}
+ /**
+ * Watcher implementation to watch the readonly bookies under
+ * <available>/readonly
+ */
+ private static class ReadOnlyBookieWatcher implements Watcher, ChildrenCallback {
+
+ private final static Logger LOG = LoggerFactory.getLogger(ReadOnlyBookieWatcher.class);
+ private HashSet<InetSocketAddress> readOnlyBookies = new HashSet<InetSocketAddress>();
+ private BookKeeper bk;
+ private String readOnlyBookieRegPath;
+
+ public ReadOnlyBookieWatcher(ClientConfiguration conf, BookKeeper bk) throws KeeperException,
+ InterruptedException {
+ this.bk = bk;
+ readOnlyBookieRegPath = conf.getZkAvailableBookiesPath() + "/" + Bookie.READONLY;
+ if (null == bk.getZkHandle().exists(readOnlyBookieRegPath, false)) {
+ try {
+ bk.getZkHandle().create(readOnlyBookieRegPath, new byte[0], Ids.OPEN_ACL_UNSAFE,
+ CreateMode.PERSISTENT);
+ } catch (NodeExistsException e) {
+ // this node is just now created by someone.
+ }
+ }
+ }
+
+ @Override
+ public void process(WatchedEvent event) {
+ readROBookies();
+ }
+
+ // read the readonly bookies in blocking fashion. Used only for first
+ // time.
+ void readROBookiesBlocking() throws InterruptedException, KeeperException {
+
+ final LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
+ readROBookies(new ChildrenCallback() {
+ public void processResult(int rc, String path, Object ctx, List<String> children) {
+ try {
+ ReadOnlyBookieWatcher.this.processResult(rc, path, ctx, children);
+ queue.put(rc);
+ } catch (InterruptedException e) {
+ logger.error("Interruped when trying to read readonly bookies in a blocking fashion");
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ int rc = queue.take();
+
+ if (rc != KeeperException.Code.OK.intValue()) {
+ throw KeeperException.create(Code.get(rc));
+ }
+ }
+
+ // Read children and register watcher for readonly bookies path
+ void readROBookies(ChildrenCallback callback) {
+ bk.getZkHandle().getChildren(this.readOnlyBookieRegPath, this, callback, null);
+ }
+
+ void readROBookies() {
+ readROBookies(this);
+ }
+
+ @Override
+ public void processResult(int rc, String path, Object ctx, List<String> children) {
+ if (rc != Code.OK.intValue()) {
+ LOG.error("Not able to read readonly bookies : ", KeeperException.create(Code.get(rc)));
+ return;
+ }
+
+ HashSet<InetSocketAddress> newReadOnlyBookies = convertToBookieAddresses(children);
+ readOnlyBookies = newReadOnlyBookies;
+ }
+
+ // returns the readonly bookies
+ public HashSet<InetSocketAddress> getReadOnlyBookies() {
+ return readOnlyBookies;
+ }
+ }
}
Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java?rev=1416590&r1=1416589&r2=1416590&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java Mon Dec 3 16:59:04 2012
@@ -558,6 +558,9 @@ public class PerChannelBookieClient exte
case BookieProtocol.EUA:
rc = BKException.Code.UnauthorizedAccessException;
break;
+ case BookieProtocol.EREADONLY:
+ rc = BKException.Code.WriteOnReadOnlyBookieException;
+ break;
default:
LOG.error("Add for ledger: " + ledgerId + ", entry: " + entryId + " failed on bookie: " + addr
+ " with code: " + rc);
Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ReadOnlyBookieTest.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ReadOnlyBookieTest.java?rev=1416590&r1=1416589&r2=1416590&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ReadOnlyBookieTest.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/ReadOnlyBookieTest.java Mon Dec 3 16:59:04 2012
@@ -167,4 +167,21 @@ public class ReadOnlyBookieTest extends
bsConfs.add(newConf);
bs.add(startBookie(newConf));
}
+
+ /**
+ * Test ledger creation with readonly bookies
+ */
+ public void testLedgerCreationShouldFailWithReadonlyBookie() throws Exception {
+ killBookie(1);
+ baseConf.setReadOnlyModeEnabled(true);
+ startNewBookie();
+ bs.get(1).getBookie().transitionToReadOnlyMode();
+ try {
+ bkc.readBookiesBlocking();
+ bkc.createLedger(2, 2, DigestType.CRC32, "".getBytes());
+ fail("Must throw exception, as there is one readonly bookie");
+ } catch (BKException e) {
+ // Expected
+ }
+ }
}