Return-Path: X-Original-To: apmail-zookeeper-commits-archive@www.apache.org Delivered-To: apmail-zookeeper-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 53E12DC8B for ; Wed, 18 Jul 2012 15:01:14 +0000 (UTC) Received: (qmail 83742 invoked by uid 500); 18 Jul 2012 15:01:14 -0000 Delivered-To: apmail-zookeeper-commits-archive@zookeeper.apache.org Received: (qmail 83192 invoked by uid 500); 18 Jul 2012 15:01:11 -0000 Mailing-List: contact commits-help@zookeeper.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ Delivered-To: mailing list commits@zookeeper.apache.org Received: (qmail 83152 invoked by uid 99); 18 Jul 2012 15:01:10 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 18 Jul 2012 15:01:10 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 18 Jul 2012 15:01:07 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 6D45B2388ABA for ; Wed, 18 Jul 2012 15:00:48 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit 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 -0000 To: commits@zookeeper.apache.org From: sijie@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120718150048.6D45B2388ABA@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 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> 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 addrs = new ArrayList(); 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 + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + 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 createdLedgers) { final AtomicInteger expected = new AtomicInteger(numLedgers); for (int i=0; i() { + getLedgerManager().createLedger(new LedgerMetadata(1, 1, DigestType.MAC, "".getBytes()), + new GenericCallback() { @Override public void operationComplete(int rc, Long ledgerId) { if (rc == BKException.Code.OK) {