zookeeper-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From si...@apache.org
Subject svn commit: r1362974 - in /zookeeper/bookkeeper/trunk: ./ bookkeeper-server/src/main/java/org/apache/bookkeeper/client/ bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/ bookkeeper-server/src/main/proto/ bookkeeper-server/src/test/java/org/a...
Date Wed, 18 Jul 2012 15:00:47 GMT
Author: sijie
Date: Wed Jul 18 15:00:47 2012
New Revision: 1362974

URL: http://svn.apache.org/viewvc?rev=1362974&view=rev
Log:
BOOKKEEPER-2: bookkeeper does not put enough meta-data in to do recovery properly (ivank via sijie)

Modified:
    zookeeper/bookkeeper/trunk/CHANGES.txt
    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/DigestManager.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerCreateOp.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerMetadata.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerOpenOp.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/DataFormats.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/proto/DataFormats.proto
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTest.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryTest.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/GcLedgersTest.java

Modified: zookeeper/bookkeeper/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/CHANGES.txt?rev=1362974&r1=1362973&r2=1362974&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/CHANGES.txt (original)
+++ zookeeper/bookkeeper/trunk/CHANGES.txt Wed Jul 18 15:00:47 2012
@@ -54,6 +54,8 @@ Trunk (unreleased changes)
 
         BOOKKEEPER-328: Bookie DeathWatcher is missing thread name (Rakesh via sijie)
 
+        BOOKKEEPER-2: bookkeeper does not put enough meta-data in to do recovery properly (ivank via sijie)
+
       hedwig-server:
 
         BOOKKEEPER-250: Need a ledger manager like interface to manage metadata operations in Hedwig (sijie via ivank)

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=1362974&r1=1362973&r2=1362974&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 Wed Jul 18 15:00:47 2012
@@ -37,7 +37,6 @@ import org.apache.bookkeeper.conf.Client
 import org.apache.bookkeeper.client.AsyncCallback.OpenCallback;
 import org.apache.bookkeeper.client.AsyncCallback.ReadCallback;
 import org.apache.bookkeeper.client.AsyncCallback.RecoverCallback;
-import org.apache.bookkeeper.client.BookKeeper.DigestType;
 import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback;
 import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.MultiCallback;
 import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.Processor;
@@ -51,7 +50,6 @@ import org.apache.zookeeper.WatchedEvent
 import org.apache.zookeeper.Watcher;
 import org.apache.zookeeper.ZooKeeper;
 import org.apache.zookeeper.KeeperException.Code;
-import org.apache.zookeeper.data.Stat;
 import org.jboss.netty.buffer.ChannelBuffer;
 
 /**
@@ -76,16 +74,6 @@ public class BookKeeperAdmin {
      */
     private Random rand = new Random();
 
-    /*
-     * For now, assume that all ledgers were created with the same DigestType
-     * and password. In the future, this admin tool will need to know for each
-     * ledger, what was the DigestType and password used to create it before it
-     * can open it. These values will come from System properties, though hard
-     * coded defaults are defined here.
-     */
-    private DigestType DIGEST_TYPE;
-    private byte[] PASSWD;
-
     /**
      * Constructor that takes in a ZooKeeper servers connect string so we know
      * how to connect to ZooKeeper to retrieve information about the BookKeeper
@@ -147,9 +135,6 @@ public class BookKeeperAdmin {
         bookiesPath = conf.getZkAvailableBookiesPath();
         // Create the BookKeeper client instance
         bkc = new BookKeeper(conf, zk);
-
-        DIGEST_TYPE = conf.getBookieRecoveryDigestType();
-        PASSWD = conf.getBookieRecoveryPasswd();
     }
 
     /**
@@ -165,31 +150,38 @@ public class BookKeeperAdmin {
     }
 
     /**
-     * Method to get the input ledger's digest type. For now, this is just a
-     * placeholder function since there is no way we can get this information
-     * easily. In the future, BookKeeper should store this ledger metadata
-     * somewhere such that an admin tool can access it.
+     * Open a ledger as an administrator. This means that no digest password
+     * checks are done. Otherwise, the call is identical to BookKeeper#asyncOpenLedger
+     *
+     * @param lId
+     *          ledger identifier
+     * @param cb
+     *          Callback which will receive a LedgerHandle object
+     * @param ctx
+     *          optional context object, to be passwd to the callback (can be null)
      *
-     * @param ledgerId
-     *            LedgerId we are retrieving the digestType for.
-     * @return DigestType for the input ledger
+     * @see BookKeeper#asyncOpenLedger
      */
-    private DigestType getLedgerDigestType(long ledgerId) {
-        return DIGEST_TYPE;
+    public void asyncOpenLedger(final long lId, final OpenCallback cb, final Object ctx) {
+        new LedgerOpenOp(bkc, lId, cb, ctx).initiate();
     }
 
     /**
-     * Method to get the input ledger's password. For now, this is just a
-     * placeholder function since there is no way we can get this information
-     * easily. In the future, BookKeeper should store this ledger metadata
-     * somewhere such that an admin tool can access it.
+     * Open a ledger as an administrator without recovering the ledger. This means
+     * that no digest password  checks are done. Otherwise, the call is identical
+     * to BookKeeper#asyncOpenLedgerNoRecovery
      *
-     * @param ledgerId
-     *            LedgerId we are retrieving the password for.
-     * @return Password for the input ledger
+     * @param lId
+     *          ledger identifier
+     * @param cb
+     *          Callback which will receive a LedgerHandle object
+     * @param ctx
+     *          optional context object, to be passwd to the callback (can be null)
+     *
+     * @see BookKeeper#asyncOpenLedgerNoRecovery
      */
-    private byte[] getLedgerPasswd(long ledgerId) {
-        return PASSWD;
+    public void asyncOpenLedgerNoRecovery(final long lId, final OpenCallback cb, final Object ctx) {
+        new LedgerOpenOp(bkc, lId, cb, ctx).initiateWithoutRecovery();
     }
 
     // Object used for calling async methods and waiting for them to complete.
@@ -430,15 +422,8 @@ public class BookKeeperAdmin {
         if (LOG.isDebugEnabled()) {
             LOG.debug("Recovering ledger : " + lId);
         }
-        /*
-         * For the current ledger, open it to retrieve the LedgerHandle. This
-         * will contain the LedgerMetadata indicating which bookie servers the
-         * ledger fragments are stored on. Check if any of the ledger fragments
-         * for the current ledger are stored on the input dead bookie.
-         */
-        final DigestType digestType = getLedgerDigestType(lId);
-        final byte[] passwd = getLedgerPasswd(lId);
-        bkc.asyncOpenLedgerNoRecovery(lId, digestType, passwd, new OpenCallback() {
+
+        asyncOpenLedgerNoRecovery(lId, new OpenCallback() {
             @Override
             public void openComplete(int rc, final LedgerHandle lh, Object ctx) {
                 if (rc != Code.OK.intValue()) {
@@ -463,7 +448,7 @@ public class BookKeeperAdmin {
                         } catch (Exception ie) {
                             LOG.warn("Error closing non recovery ledger handle for ledger " + lId, ie);
                         }
-                        bkc.asyncOpenLedger(lId, digestType, passwd, new OpenCallback() {
+                        asyncOpenLedger(lId, new OpenCallback() {
                             @Override
                             public void openComplete(int newrc, final LedgerHandle newlh, Object newctx) {
                                 if (newrc != Code.OK.intValue()) {

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/DigestManager.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/DigestManager.java?rev=1362974&r1=1362973&r2=1362974&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/DigestManager.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/DigestManager.java Wed Jul 18 15:00:47 2012
@@ -116,6 +116,13 @@ abstract class DigestManager {
         ByteBuffer dataReceivedBuffer = dataReceived.toByteBuffer();
         byte[] digest;
 
+        if ((METADATA_LENGTH + macCodeLength) > dataReceived.readableBytes()) {
+            logger.error("Data received is smaller than the minimum for this digest type. "
+                    + " Either the packet it corrupt, or the wrong digest is configured. "
+                    + " Digest type: {}, Packet Length: {}",
+                    this.getClass().getName(), dataReceived.readableBytes());
+            throw new BKDigestMatchException();
+        }
         update(dataReceivedBuffer.array(), dataReceivedBuffer.position(), METADATA_LENGTH);
 
         int offset = METADATA_LENGTH + macCodeLength;

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerCreateOp.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerCreateOp.java?rev=1362974&r1=1362973&r2=1362974&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerCreateOp.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerCreateOp.java Wed Jul 18 15:00:47 2012
@@ -21,7 +21,6 @@
 
 package org.apache.bookkeeper.client;
 
-import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.security.GeneralSecurityException;
 import java.util.ArrayList;
@@ -71,7 +70,7 @@ class LedgerCreateOp implements GenericC
 
     LedgerCreateOp(BookKeeper bk, int ensembleSize, int quorumSize, DigestType digestType, byte[] passwd, CreateCallback cb, Object ctx) {
         this.bk = bk;
-        this.metadata = new LedgerMetadata(ensembleSize, quorumSize);
+        this.metadata = new LedgerMetadata(ensembleSize, quorumSize, digestType, passwd);
         this.digestType = digestType;
         this.passwd = passwd;
         this.cb = cb;

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerMetadata.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerMetadata.java?rev=1362974&r1=1362973&r2=1362974&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerMetadata.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerMetadata.java Wed Jul 18 15:00:47 2012
@@ -27,12 +27,13 @@ import java.util.Iterator;
 import java.util.Map;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import java.util.Arrays;
 
 import org.apache.bookkeeper.versioning.Version;
 import com.google.protobuf.TextFormat;
+import com.google.protobuf.ByteString;
 import org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat;
 import org.apache.bookkeeper.util.StringUtils;
-import org.apache.zookeeper.data.Stat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -69,7 +70,12 @@ public class LedgerMetadata {
     ArrayList<InetSocketAddress> currentEnsemble;
     volatile Version version = null;
 
-    public LedgerMetadata(int ensembleSize, int quorumSize) {
+    private boolean hasPassword = false;
+    private LedgerMetadataFormat.DigestType digestType;
+    private byte[] password;
+
+    public LedgerMetadata(int ensembleSize, int quorumSize,
+                          BookKeeper.DigestType digestType, byte[] password) {
         this.ensembleSize = ensembleSize;
         this.quorumSize = quorumSize;
 
@@ -81,10 +87,16 @@ public class LedgerMetadata {
         this.state = LedgerMetadataFormat.State.OPEN;
         this.lastEntryId = LedgerHandle.INVALID_ENTRY_ID;
         this.metadataFormatVersion = CURRENT_METADATA_FORMAT_VERSION;
-    };
+
+        this.digestType = digestType.equals(BookKeeper.DigestType.MAC) ?
+            LedgerMetadataFormat.DigestType.HMAC : LedgerMetadataFormat.DigestType.CRC32;
+        this.password = Arrays.copyOf(password, password.length);
+        this.hasPassword = true;
+    }
 
     private LedgerMetadata() {
-        this(0, 0);
+        this(0, 0, BookKeeper.DigestType.MAC, new byte[] {});
+        this.hasPassword = false;
     }
 
     /**
@@ -106,6 +118,28 @@ public class LedgerMetadata {
         return quorumSize;
     }
 
+    /**
+     * In versions 4.1.0 and below, the digest type and password were not
+     * stored in the metadata.
+     *
+     * @return whether the password has been stored in the metadata
+     */
+    boolean hasPassword() {
+        return hasPassword;
+    }
+
+    byte[] getPassword() {
+        return Arrays.copyOf(password, password.length);
+    }
+
+    BookKeeper.DigestType getDigestType() {
+        if (digestType.equals(LedgerMetadataFormat.DigestType.HMAC)) {
+            return BookKeeper.DigestType.MAC;
+        } else {
+            return BookKeeper.DigestType.CRC32;
+        }
+    }
+
     public long getLastEntryId() {
         return lastEntryId;
     }
@@ -185,6 +219,11 @@ public class LedgerMetadata {
         LedgerMetadataFormat.Builder builder = LedgerMetadataFormat.newBuilder();
         builder.setQuorumSize(quorumSize).setEnsembleSize(ensembleSize).setLength(length)
             .setState(state).setLastEntryId(lastEntryId);
+
+        if (hasPassword) {
+            builder.setDigestType(digestType).setPassword(ByteString.copyFrom(password));
+        }
+
         for (Map.Entry<Long, ArrayList<InetSocketAddress>> entry : ensembles.entrySet()) {
             LedgerMetadataFormat.Segment.Builder segmentBuilder = LedgerMetadataFormat.Segment.newBuilder();
             segmentBuilder.setFirstEntryId(entry.getKey());
@@ -288,6 +327,12 @@ public class LedgerMetadata {
         lc.state = data.getState();
         lc.lastEntryId = data.getLastEntryId();
 
+        if (data.hasPassword()) {
+            lc.digestType = data.getDigestType();
+            lc.password = data.getPassword().toByteArray();
+            lc.hasPassword = true;
+        }
+
         for (LedgerMetadataFormat.Segment s : data.getSegmentList()) {
             ArrayList<InetSocketAddress> addrs = new ArrayList<InetSocketAddress>();
             for (String member : s.getEnsembleMemberList()) {
@@ -370,7 +415,9 @@ public class LedgerMetadata {
             ensembleSize != newMeta.ensembleSize ||
             quorumSize != newMeta.quorumSize ||
             length != newMeta.length ||
-            state != newMeta.state) {
+            state != newMeta.state ||
+            !digestType.equals(newMeta.digestType) ||
+            !Arrays.equals(password, newMeta.password)) {
             return false;
         }
         if (state == LedgerMetadataFormat.State.CLOSED

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerOpenOp.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerOpenOp.java?rev=1362974&r1=1362973&r2=1362974&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerOpenOp.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerOpenOp.java Wed Jul 18 15:00:47 2012
@@ -21,7 +21,7 @@
 
 package org.apache.bookkeeper.client;
 
-import java.io.IOException;
+import java.util.Arrays;
 import java.security.GeneralSecurityException;
 
 import org.apache.bookkeeper.client.AsyncCallback.OpenCallback;
@@ -46,7 +46,8 @@ class LedgerOpenOp implements GenericCal
     LedgerHandle lh;
     final byte[] passwd;
     final DigestType digestType;
-    boolean doRecovery;
+    boolean doRecovery = true;
+    boolean administrativeOpen = false;
 
     /**
      * Constructor.
@@ -58,7 +59,7 @@ class LedgerOpenOp implements GenericCal
      * @param cb
      * @param ctx
      */
-    public LedgerOpenOp(BookKeeper bk, long ledgerId, DigestType digestType, byte[] passwd, 
+    public LedgerOpenOp(BookKeeper bk, long ledgerId, DigestType digestType, byte[] passwd,
                         OpenCallback cb, Object ctx) {
         this.bk = bk;
         this.ledgerId = ledgerId;
@@ -66,8 +67,17 @@ class LedgerOpenOp implements GenericCal
         this.cb = cb;
         this.ctx = ctx;
         this.digestType = digestType;
+    }
 
-        this.doRecovery = true;
+    public LedgerOpenOp(BookKeeper bk, long ledgerId, OpenCallback cb, Object ctx) {
+        this.bk = bk;
+        this.ledgerId = ledgerId;
+        this.cb = cb;
+        this.ctx = ctx;
+
+        this.passwd = bk.getConf().getBookieRecoveryPasswd();
+        this.digestType = bk.getConf().getBookieRecoveryDigestType();
+        this.administrativeOpen = true;
     }
 
     /**
@@ -97,6 +107,34 @@ class LedgerOpenOp implements GenericCal
             cb.openComplete(rc, null, this.ctx);
             return;
         }
+
+        final byte[] passwd;
+        final DigestType digestType;
+
+        /* For an administrative open, the default passwords
+         * are read from the configuration, but if the metadata
+         * already contains passwords, use these instead. */
+        if (administrativeOpen && metadata.hasPassword()) {
+            passwd = metadata.getPassword();
+            digestType = metadata.getDigestType();
+        } else {
+            passwd = this.passwd;
+            digestType = this.digestType;
+
+            if (metadata.hasPassword()) {
+                if (!Arrays.equals(passwd, metadata.getPassword())) {
+                    LOG.error("Provided passwd does not match that in metadata");
+                    cb.openComplete(BKException.Code.UnauthorizedAccessException, null, this.ctx);
+                    return;
+                }
+                if (digestType != metadata.getDigestType()) {
+                    LOG.error("Provided digest does not match that in metadata");
+                    cb.openComplete(BKException.Code.DigestMatchException, null, this.ctx);
+                    return;
+                }
+            }
+        }
+
         // get the ledger metadata back
         try {
             lh = new ReadOnlyLedgerHandle(bk, ledgerId, metadata, digestType, passwd);

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/DataFormats.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/DataFormats.java?rev=1362974&r1=1362973&r2=1362974&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/DataFormats.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/DataFormats.java Wed Jul 18 15:00:47 2012
@@ -40,6 +40,14 @@ public final class DataFormats {
         getSegmentOrBuilderList();
     org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.SegmentOrBuilder getSegmentOrBuilder(
         int index);
+    
+    // optional .LedgerMetadataFormat.DigestType digestType = 7;
+    boolean hasDigestType();
+    org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType getDigestType();
+    
+    // optional bytes password = 8;
+    boolean hasPassword();
+    com.google.protobuf.ByteString getPassword();
   }
   public static final class LedgerMetadataFormat extends
       com.google.protobuf.GeneratedMessage
@@ -141,6 +149,75 @@ public final class DataFormats {
       // @@protoc_insertion_point(enum_scope:LedgerMetadataFormat.State)
     }
     
+    public enum DigestType
+        implements com.google.protobuf.ProtocolMessageEnum {
+      CRC32(0, 1),
+      HMAC(1, 2),
+      ;
+      
+      public static final int CRC32_VALUE = 1;
+      public static final int HMAC_VALUE = 2;
+      
+      
+      public final int getNumber() { return value; }
+      
+      public static DigestType valueOf(int value) {
+        switch (value) {
+          case 1: return CRC32;
+          case 2: return HMAC;
+          default: return null;
+        }
+      }
+      
+      public static com.google.protobuf.Internal.EnumLiteMap<DigestType>
+          internalGetValueMap() {
+        return internalValueMap;
+      }
+      private static com.google.protobuf.Internal.EnumLiteMap<DigestType>
+          internalValueMap =
+            new com.google.protobuf.Internal.EnumLiteMap<DigestType>() {
+              public DigestType findValueByNumber(int number) {
+                return DigestType.valueOf(number);
+              }
+            };
+      
+      public final com.google.protobuf.Descriptors.EnumValueDescriptor
+          getValueDescriptor() {
+        return getDescriptor().getValues().get(index);
+      }
+      public final com.google.protobuf.Descriptors.EnumDescriptor
+          getDescriptorForType() {
+        return getDescriptor();
+      }
+      public static final com.google.protobuf.Descriptors.EnumDescriptor
+          getDescriptor() {
+        return org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.getDescriptor().getEnumTypes().get(1);
+      }
+      
+      private static final DigestType[] VALUES = {
+        CRC32, HMAC, 
+      };
+      
+      public static DigestType valueOf(
+          com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
+        if (desc.getType() != getDescriptor()) {
+          throw new java.lang.IllegalArgumentException(
+            "EnumValueDescriptor is not for this type.");
+        }
+        return VALUES[desc.getIndex()];
+      }
+      
+      private final int index;
+      private final int value;
+      
+      private DigestType(int index, int value) {
+        this.index = index;
+        this.value = value;
+      }
+      
+      // @@protoc_insertion_point(enum_scope:LedgerMetadataFormat.DigestType)
+    }
+    
     public interface SegmentOrBuilder
         extends com.google.protobuf.MessageOrBuilder {
       
@@ -670,6 +747,26 @@ public final class DataFormats {
       return segment_.get(index);
     }
     
+    // optional .LedgerMetadataFormat.DigestType digestType = 7;
+    public static final int DIGESTTYPE_FIELD_NUMBER = 7;
+    private org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType digestType_;
+    public boolean hasDigestType() {
+      return ((bitField0_ & 0x00000020) == 0x00000020);
+    }
+    public org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType getDigestType() {
+      return digestType_;
+    }
+    
+    // optional bytes password = 8;
+    public static final int PASSWORD_FIELD_NUMBER = 8;
+    private com.google.protobuf.ByteString password_;
+    public boolean hasPassword() {
+      return ((bitField0_ & 0x00000040) == 0x00000040);
+    }
+    public com.google.protobuf.ByteString getPassword() {
+      return password_;
+    }
+    
     private void initFields() {
       quorumSize_ = 0;
       ensembleSize_ = 0;
@@ -677,6 +774,8 @@ public final class DataFormats {
       lastEntryId_ = 0L;
       state_ = org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.State.OPEN;
       segment_ = java.util.Collections.emptyList();
+      digestType_ = org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType.CRC32;
+      password_ = com.google.protobuf.ByteString.EMPTY;
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -730,6 +829,12 @@ public final class DataFormats {
       for (int i = 0; i < segment_.size(); i++) {
         output.writeMessage(6, segment_.get(i));
       }
+      if (((bitField0_ & 0x00000020) == 0x00000020)) {
+        output.writeEnum(7, digestType_.getNumber());
+      }
+      if (((bitField0_ & 0x00000040) == 0x00000040)) {
+        output.writeBytes(8, password_);
+      }
       getUnknownFields().writeTo(output);
     }
     
@@ -763,6 +868,14 @@ public final class DataFormats {
         size += com.google.protobuf.CodedOutputStream
           .computeMessageSize(6, segment_.get(i));
       }
+      if (((bitField0_ & 0x00000020) == 0x00000020)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeEnumSize(7, digestType_.getNumber());
+      }
+      if (((bitField0_ & 0x00000040) == 0x00000040)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(8, password_);
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -904,6 +1017,10 @@ public final class DataFormats {
         } else {
           segmentBuilder_.clear();
         }
+        digestType_ = org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType.CRC32;
+        bitField0_ = (bitField0_ & ~0x00000040);
+        password_ = com.google.protobuf.ByteString.EMPTY;
+        bitField0_ = (bitField0_ & ~0x00000080);
         return this;
       }
       
@@ -971,6 +1088,14 @@ public final class DataFormats {
         } else {
           result.segment_ = segmentBuilder_.build();
         }
+        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {
+          to_bitField0_ |= 0x00000020;
+        }
+        result.digestType_ = digestType_;
+        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {
+          to_bitField0_ |= 0x00000040;
+        }
+        result.password_ = password_;
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -1028,6 +1153,12 @@ public final class DataFormats {
             }
           }
         }
+        if (other.hasDigestType()) {
+          setDigestType(other.getDigestType());
+        }
+        if (other.hasPassword()) {
+          setPassword(other.getPassword());
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -1118,6 +1249,22 @@ public final class DataFormats {
               addSegment(subBuilder.buildPartial());
               break;
             }
+            case 56: {
+              int rawValue = input.readEnum();
+              org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType value = org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType.valueOf(rawValue);
+              if (value == null) {
+                unknownFields.mergeVarintField(7, rawValue);
+              } else {
+                bitField0_ |= 0x00000040;
+                digestType_ = value;
+              }
+              break;
+            }
+            case 66: {
+              bitField0_ |= 0x00000080;
+              password_ = input.readBytes();
+              break;
+            }
           }
         }
       }
@@ -1418,6 +1565,54 @@ public final class DataFormats {
         return segmentBuilder_;
       }
       
+      // optional .LedgerMetadataFormat.DigestType digestType = 7;
+      private org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType digestType_ = org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType.CRC32;
+      public boolean hasDigestType() {
+        return ((bitField0_ & 0x00000040) == 0x00000040);
+      }
+      public org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType getDigestType() {
+        return digestType_;
+      }
+      public Builder setDigestType(org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        bitField0_ |= 0x00000040;
+        digestType_ = value;
+        onChanged();
+        return this;
+      }
+      public Builder clearDigestType() {
+        bitField0_ = (bitField0_ & ~0x00000040);
+        digestType_ = org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.DigestType.CRC32;
+        onChanged();
+        return this;
+      }
+      
+      // optional bytes password = 8;
+      private com.google.protobuf.ByteString password_ = com.google.protobuf.ByteString.EMPTY;
+      public boolean hasPassword() {
+        return ((bitField0_ & 0x00000080) == 0x00000080);
+      }
+      public com.google.protobuf.ByteString getPassword() {
+        return password_;
+      }
+      public Builder setPassword(com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000080;
+        password_ = value;
+        onChanged();
+        return this;
+      }
+      public Builder clearPassword() {
+        bitField0_ = (bitField0_ & ~0x00000080);
+        password_ = getDefaultInstance().getPassword();
+        onChanged();
+        return this;
+      }
+      
       // @@protoc_insertion_point(builder_scope:LedgerMetadataFormat)
     }
     
@@ -1448,16 +1643,19 @@ public final class DataFormats {
       descriptor;
   static {
     java.lang.String[] descriptorData = {
-      "\n src/main/proto/DataFormats.proto\"\260\002\n\024L" +
+      "\n src/main/proto/DataFormats.proto\"\233\003\n\024L" +
       "edgerMetadataFormat\022\022\n\nquorumSize\030\001 \002(\005\022" +
       "\024\n\014ensembleSize\030\002 \002(\005\022\016\n\006length\030\003 \002(\003\022\023\n" +
       "\013lastEntryId\030\004 \001(\003\0220\n\005state\030\005 \002(\0162\033.Ledg" +
       "erMetadataFormat.State:\004OPEN\022.\n\007segment\030" +
-      "\006 \003(\0132\035.LedgerMetadataFormat.Segment\0327\n\007" +
-      "Segment\022\026\n\016ensembleMember\030\001 \003(\t\022\024\n\014first" +
-      "EntryId\030\002 \002(\003\".\n\005State\022\010\n\004OPEN\020\001\022\017\n\013IN_R" +
-      "ECOVERY\020\002\022\n\n\006CLOSED\020\003B\037\n\033org.apache.book" +
-      "keeper.protoH\001"
+      "\006 \003(\0132\035.LedgerMetadataFormat.Segment\0224\n\n" +
+      "digestType\030\007 \001(\0162 .LedgerMetadataFormat." +
+      "DigestType\022\020\n\010password\030\010 \001(\014\0327\n\007Segment\022" +
+      "\026\n\016ensembleMember\030\001 \003(\t\022\024\n\014firstEntryId\030" +
+      "\002 \002(\003\".\n\005State\022\010\n\004OPEN\020\001\022\017\n\013IN_RECOVERY\020",
+      "\002\022\n\n\006CLOSED\020\003\"!\n\nDigestType\022\t\n\005CRC32\020\001\022\010" +
+      "\n\004HMAC\020\002B\037\n\033org.apache.bookkeeper.protoH" +
+      "\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -1469,7 +1667,7 @@ public final class DataFormats {
           internal_static_LedgerMetadataFormat_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_LedgerMetadataFormat_descriptor,
-              new java.lang.String[] { "QuorumSize", "EnsembleSize", "Length", "LastEntryId", "State", "Segment", },
+              new java.lang.String[] { "QuorumSize", "EnsembleSize", "Length", "LastEntryId", "State", "Segment", "DigestType", "Password", },
               org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.class,
               org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat.Builder.class);
           internal_static_LedgerMetadataFormat_Segment_descriptor =

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/proto/DataFormats.proto
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/proto/DataFormats.proto?rev=1362974&r1=1362973&r2=1362974&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/proto/DataFormats.proto (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/proto/DataFormats.proto Wed Jul 18 15:00:47 2012
@@ -36,7 +36,14 @@ message LedgerMetadataFormat {
 
     message Segment {
         repeated string ensembleMember = 1;
-        required int64 firstEntryId = 2; 
+        required int64 firstEntryId = 2;
     }
     repeated Segment segment = 6;
+
+    enum DigestType {
+        CRC32 = 1;
+        HMAC = 2;
+    }
+    optional DigestType digestType = 7;
+    optional bytes password = 8;
 }
\ No newline at end of file

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTest.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTest.java?rev=1362974&r1=1362973&r2=1362974&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTest.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperTest.java Wed Jul 18 15:00:47 2012
@@ -21,14 +21,11 @@ package org.apache.bookkeeper.client;
 *
 */
 
-import java.util.Enumeration;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
 import org.apache.bookkeeper.conf.ClientConfiguration;
 import org.apache.bookkeeper.client.BookKeeper.DigestType;
-import org.apache.bookkeeper.client.BookKeeper;
-import org.apache.bookkeeper.test.BookKeeperClusterTestCase;
+import org.apache.bookkeeper.test.BaseTestCase;
 import org.apache.zookeeper.ZooKeeper;
 import org.apache.zookeeper.Watcher;
 import org.apache.zookeeper.WatchedEvent;
@@ -41,9 +38,15 @@ import org.slf4j.LoggerFactory;
 /**
  * Tests of the main BookKeeper client
  */
-public class BookKeeperTest extends BookKeeperClusterTestCase {
-    public BookKeeperTest() {
+public class BookKeeperTest extends BaseTestCase {
+    static Logger LOG = LoggerFactory.getLogger(BookKeeperTest.class);
+
+    DigestType digestType;
+
+    public BookKeeperTest(DigestType digestType) {
         super(4);
+
+        this.digestType = digestType;
     }
 
     @Test
@@ -57,7 +60,7 @@ public class BookKeeperTest extends Book
         l.await();
 
         BookKeeper bkc = new BookKeeper(conf);
-        bkc.createLedger(DigestType.CRC32, "testPasswd".getBytes()).close();
+        bkc.createLedger(digestType, "testPasswd".getBytes()).close();
         bkc.close();
     }
 
@@ -85,4 +88,63 @@ public class BookKeeperTest extends Book
             // correct behaviour
         }
     }
-}
\ No newline at end of file
+
+    /**
+     * Test that bookkeeper is not able to open ledgers if
+     * it provides the wrong password or wrong digest
+     */
+    @Test
+    public void testBookkeeperPassword() throws Exception {
+        ClientConfiguration conf = new ClientConfiguration()
+            .setZkServers(zkUtil.getZooKeeperConnectString());
+        BookKeeper bkc = new BookKeeper(conf);
+
+        DigestType digestCorrect = digestType;
+        byte[] passwdCorrect = "AAAAAAA".getBytes();
+        DigestType digestBad = digestType == DigestType.MAC ? DigestType.CRC32 : DigestType.MAC;
+        byte[] passwdBad = "BBBBBBB".getBytes();
+
+
+        LedgerHandle lh = null;
+        try {
+            lh = bkc.createLedger(digestCorrect, passwdCorrect);
+            long id = lh.getId();
+            for (int i = 0; i < 100; i++) {
+                lh.addEntry("foobar".getBytes());
+            }
+            lh.close();
+
+            // try open with bad passwd
+            try {
+                bkc.openLedger(id, digestCorrect, passwdBad);
+                fail("Shouldn't be able to open with bad passwd");
+            } catch (BKException.BKUnauthorizedAccessException bke) {
+                // correct behaviour
+            }
+
+            // try open with bad digest
+            try {
+                bkc.openLedger(id, digestBad, passwdCorrect);
+                fail("Shouldn't be able to open with bad digest");
+            } catch (BKException.BKDigestMatchException bke) {
+                // correct behaviour
+            }
+
+            // try open with both bad
+            try {
+                bkc.openLedger(id, digestBad, passwdBad);
+                fail("Shouldn't be able to open with bad passwd and digest");
+            } catch (BKException.BKUnauthorizedAccessException bke) {
+                // correct behaviour
+            }
+
+            // try open with both correct
+            bkc.openLedger(id, digestCorrect, passwdCorrect).close();
+        } finally {
+            if (lh != null) {
+                lh.close();
+            }
+            bkc.close();
+        }
+    }
+}

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryTest.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryTest.java?rev=1362974&r1=1362973&r2=1362974&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryTest.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookieRecoveryTest.java Wed Jul 18 15:00:47 2012
@@ -32,7 +32,6 @@ import java.util.HashSet;
 import java.util.HashMap;
 import java.util.Collections;
 import java.util.Random;
-import java.util.concurrent.atomic.AtomicInteger;
 
 import org.jboss.netty.buffer.ChannelBuffer;
 import java.util.concurrent.atomic.AtomicLong;
@@ -41,16 +40,10 @@ import java.util.concurrent.TimeUnit;
 import org.apache.bookkeeper.test.MultiLedgerManagerMultiDigestTestCase;
 import org.apache.bookkeeper.conf.ClientConfiguration;
 import org.apache.bookkeeper.conf.ServerConfiguration;
-import org.apache.bookkeeper.client.AsyncCallback.AddCallback;
-import org.apache.bookkeeper.client.BKException;
-import org.apache.bookkeeper.client.LedgerEntry;
-import org.apache.bookkeeper.client.LedgerHandle;
-import org.apache.bookkeeper.proto.BookieProtocol;
 import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback;
 import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ReadEntryCallback;
 import org.apache.bookkeeper.client.AsyncCallback.RecoverCallback;
 import org.apache.bookkeeper.client.BookKeeper.DigestType;
-import org.apache.bookkeeper.client.BookKeeperAdmin;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.junit.After;
@@ -90,6 +83,7 @@ public class BookieRecoveryTest extends 
 
     // Objects to use for this jUnit test.
     DigestType digestType;
+    String ledgerManagerFactory;
     SyncObject sync;
     BookieRecoverCallback bookieRecoverCb;
     BookKeeperAdmin bkAdmin;
@@ -98,6 +92,7 @@ public class BookieRecoveryTest extends 
     public BookieRecoveryTest(String ledgerManagerFactory, DigestType digestType) {
         super(3);
         this.digestType = digestType;
+        this.ledgerManagerFactory = ledgerManagerFactory;
         LOG.info("Using ledger manager " + ledgerManagerFactory);
         // set ledger manager
         baseConf.setLedgerManagerFactoryClassName(ledgerManagerFactory);
@@ -759,4 +754,181 @@ public class BookieRecoveryTest extends 
             }
         }
     }
+
+    @Test
+    public void recoverWithoutPasswordInConf() throws Exception {
+        byte[] passwdCorrect = "AAAAAA".getBytes();
+        byte[] passwdBad = "BBBBBB".getBytes();
+        DigestType digestCorrect = digestType;
+        DigestType digestBad = (digestType == DigestType.MAC) ? DigestType.CRC32 : DigestType.MAC;
+
+        LedgerHandle lh = bkc.createLedger(3, 2, digestCorrect, passwdCorrect);
+        long ledgerId = lh.getId();
+        for (int i = 0; i < 100; i++) {
+            lh.addEntry("foobar".getBytes());
+        }
+        lh.close();
+
+        InetSocketAddress bookieSrc = bs.get(0).getLocalAddress();
+        bs.get(0).shutdown();
+        bs.remove(0);
+        startNewBookie();
+
+        // Check that entries are missing
+        lh = bkc.openLedgerNoRecovery(ledgerId, digestCorrect, passwdCorrect);
+        assertFalse("Should be entries missing", verifyFullyReplicated(lh, 100));
+        lh.close();
+
+        // Try to recover with bad password in conf
+        // This is fine, because it only falls back to the configured
+        // password if the password info is missing from the metadata
+        ClientConfiguration adminConf = new ClientConfiguration();
+        adminConf.setZkServers(zkUtil.getZooKeeperConnectString());
+        adminConf.setBookieRecoveryDigestType(digestCorrect);
+        adminConf.setBookieRecoveryPasswd(passwdBad);
+
+        BookKeeperAdmin bka = new BookKeeperAdmin(adminConf);
+        bka.recoverBookieData(bookieSrc, null);
+        bka.close();
+
+        lh = bkc.openLedgerNoRecovery(ledgerId, digestCorrect, passwdCorrect);
+        assertTrue("Should be back to fully replication", verifyFullyReplicated(lh, 100));
+        lh.close();
+
+        bookieSrc = bs.get(0).getLocalAddress();
+        bs.get(0).shutdown();
+        bs.remove(0);
+        startNewBookie();
+
+        // Check that entries are missing
+        lh = bkc.openLedgerNoRecovery(ledgerId, digestCorrect, passwdCorrect);
+        assertFalse("Should be entries missing", verifyFullyReplicated(lh, 100));
+        lh.close();
+
+        // Try to recover with no password in conf
+        adminConf = new ClientConfiguration();
+        adminConf.setZkServers(zkUtil.getZooKeeperConnectString());
+
+        bka = new BookKeeperAdmin(adminConf);
+        bka.recoverBookieData(bookieSrc, null);
+        bka.close();
+
+        lh = bkc.openLedgerNoRecovery(ledgerId, digestCorrect, passwdCorrect);
+        assertTrue("Should be back to fully replication", verifyFullyReplicated(lh, 100));
+        lh.close();
+    }
+
+    /**
+     * Test that when we try to recover a ledger which doesn't have
+     * the password stored in the configuration, we don't succeed
+     */
+    @Test
+    public void ensurePasswordUsedForOldLedgers() throws Exception {
+        // stop all bookies
+        // and wipe the ledger layout so we can use an old client
+        zkUtil.getZooKeeperClient().delete("/ledgers/LAYOUT", -1);
+
+        byte[] passwdCorrect = "AAAAAA".getBytes();
+        byte[] passwdBad = "BBBBBB".getBytes();
+        DigestType digestCorrect = digestType;
+        DigestType digestBad = digestCorrect == DigestType.MAC ? DigestType.CRC32 : DigestType.MAC;
+
+        org.apache.bk_v4_1_0.bookkeeper.client.BookKeeper.DigestType digestCorrect410
+            = org.apache.bk_v4_1_0.bookkeeper.client.BookKeeper.DigestType.valueOf(digestType.toString());
+
+        org.apache.bk_v4_1_0.bookkeeper.conf.ClientConfiguration c
+            = new org.apache.bk_v4_1_0.bookkeeper.conf.ClientConfiguration();
+        c.setZkServers(zkUtil.getZooKeeperConnectString())
+            .setLedgerManagerType(
+                    ledgerManagerFactory.equals("org.apache.bookkeeper.meta.FlatLedgerManagerFactory") ?
+                    "flat" : "hierarchical");
+
+        // create client to set up layout, close it, restart bookies, and open a new client.
+        // the new client is necessary to ensure that it has all the restarted bookies in the
+        // its available bookie list
+        org.apache.bk_v4_1_0.bookkeeper.client.BookKeeper bkc41
+            = new org.apache.bk_v4_1_0.bookkeeper.client.BookKeeper(c);
+        bkc41.close();
+        restartBookies();
+        bkc41 = new org.apache.bk_v4_1_0.bookkeeper.client.BookKeeper(c);
+
+        org.apache.bk_v4_1_0.bookkeeper.client.LedgerHandle lh41
+            = bkc41.createLedger(3, 2, digestCorrect410, passwdCorrect);
+        long ledgerId = lh41.getId();
+        for (int i = 0; i < 100; i++) {
+            lh41.addEntry("foobar".getBytes());
+        }
+        lh41.close();
+        bkc41.close();
+
+        // Startup a new bookie server
+        int newBookiePort = startNewBookie();
+        int removeIndex = 0;
+        InetSocketAddress bookieSrc = bs.get(removeIndex).getLocalAddress();
+        bs.get(removeIndex).shutdown();
+        bs.remove(removeIndex);
+
+        // Check that entries are missing
+        LedgerHandle lh = bkc.openLedgerNoRecovery(ledgerId, digestCorrect, passwdCorrect);
+        assertFalse("Should be entries missing", verifyFullyReplicated(lh, 100));
+        lh.close();
+
+        // Try to recover with bad password in conf
+        // if the digest type is MAC
+        // for CRC32, the password is only checked
+        // when adding new entries, which recovery will
+        // never do
+        ClientConfiguration adminConf;
+        BookKeeperAdmin bka;
+        if (digestCorrect == DigestType.MAC) {
+            adminConf = new ClientConfiguration();
+            adminConf.setZkServers(zkUtil.getZooKeeperConnectString());
+            adminConf.setLedgerManagerFactoryClassName(ledgerManagerFactory);
+            adminConf.setBookieRecoveryDigestType(digestCorrect);
+            adminConf.setBookieRecoveryPasswd(passwdBad);
+
+            bka = new BookKeeperAdmin(adminConf);
+            try {
+                bka.recoverBookieData(bookieSrc, null);
+                fail("Shouldn't be able to recover with wrong password");
+            } catch (BKException bke) {
+                // correct behaviour
+            } finally {
+                bka.close();
+            }
+        }
+
+        // Try to recover with bad digest in conf
+        adminConf = new ClientConfiguration();
+        adminConf.setZkServers(zkUtil.getZooKeeperConnectString());
+        adminConf.setLedgerManagerFactoryClassName(ledgerManagerFactory);
+        adminConf.setBookieRecoveryDigestType(digestBad);
+        adminConf.setBookieRecoveryPasswd(passwdCorrect);
+
+        bka = new BookKeeperAdmin(adminConf);
+        try {
+            bka.recoverBookieData(bookieSrc, null);
+            fail("Shouldn't be able to recover with wrong digest");
+        } catch (BKException bke) {
+            // correct behaviour
+        } finally {
+            bka.close();
+        }
+
+        // Check that entries are still missing
+        lh = bkc.openLedgerNoRecovery(ledgerId, digestCorrect, passwdCorrect);
+        assertFalse("Should be entries missing", verifyFullyReplicated(lh, 100));
+        lh.close();
+
+        adminConf.setBookieRecoveryDigestType(digestCorrect);
+        adminConf.setBookieRecoveryPasswd(passwdCorrect);
+
+        bka = new BookKeeperAdmin(adminConf);
+        bka.recoverBookieData(bookieSrc, null);
+        bka.close();
+
+        lh = bkc.openLedgerNoRecovery(ledgerId, digestCorrect, passwdCorrect);
+        assertTrue("Should have recovered everything", verifyFullyReplicated(lh, 100));
+        lh.close();
+    }
 }

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/GcLedgersTest.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/GcLedgersTest.java?rev=1362974&r1=1362973&r2=1362974&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/GcLedgersTest.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/GcLedgersTest.java Wed Jul 18 15:00:47 2012
@@ -21,7 +21,6 @@
 
 package org.apache.bookkeeper.meta;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -33,6 +32,7 @@ import java.util.concurrent.atomic.Atomi
 
 import org.apache.bookkeeper.client.BKException;
 import org.apache.bookkeeper.client.LedgerMetadata;
+import org.apache.bookkeeper.client.BookKeeper.DigestType;
 import org.apache.bookkeeper.meta.ActiveLedgerManager.GarbageCollector;
 import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.GenericCallback;
 import org.slf4j.Logger;
@@ -56,7 +56,8 @@ public class GcLedgersTest extends Ledge
     private void createLedgers(int numLedgers, final Set<Long> createdLedgers) {
         final AtomicInteger expected = new AtomicInteger(numLedgers);
         for (int i=0; i<numLedgers; i++) {
-            getLedgerManager().createLedger(new LedgerMetadata(1, 1), new GenericCallback<Long>() {
+            getLedgerManager().createLedger(new LedgerMetadata(1, 1, DigestType.MAC, "".getBytes()),
+                new GenericCallback<Long>() {
                 @Override
                 public void operationComplete(int rc, Long ledgerId) {
                     if (rc == BKException.Code.OK) {



Mime
View raw message