This is an automated email from the ASF dual-hosted git repository.

zhaijia pushed a commit to branch branch-4.6
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git


The following commit(s) were added to refs/heads/branch-4.6 by this push:
     new 17cb7bc  ISSUE #787: Client should be able to get ledger metadata from 
Handles.
17cb7bc is described below

commit 17cb7bc7e4a76393437580f1454fdff40346919a
Author: Sijie Guo <si...@apache.org>
AuthorDate: Fri Dec 1 22:13:49 2017 +0800

    ISSUE #787: Client should be able to get ledger metadata from Handles.
    
    Descriptions of the changes in this PR:
    
    - create a `LedgerMetadata` interface for exposing public information
    - add `getLedgerMetadata` to Handle, so both WriteHandle and ReadHandle are 
able to access the metadata.
    
    Author: Sijie Guo <si...@apache.org>
    
    Reviewers: Ivan Kelly <iv...@apache.org>, Enrico Olivelli 
<eolive...@gmail.com>, Jia Zhai <None>
    
    This closes #788 from sijie/ledger_metadata_interface, closes #787
    
    (cherry picked from commit 5f3496f740629ba4ea0d0abb3272ca2e6d8ccba7)
    Signed-off-by: Jia Zhai <zhai...@apache.org>
---
 .../org/apache/bookkeeper/client/LedgerHandle.java |   5 +-
 .../apache/bookkeeper/client/LedgerMetadata.java   |  39 +++++--
 .../org/apache/bookkeeper/client/LedgerOpenOp.java |  10 +-
 .../org/apache/bookkeeper/client/api/Handle.java   |  11 ++
 .../bookkeeper/client/api/LedgerMetadata.java      | 121 +++++++++++++++++++++
 .../bookkeeper/client/LedgerMetadataTest.java      |  33 ++++++
 .../apache/bookkeeper/client/TestSequenceRead.java |   2 +-
 .../main/resources/bookkeeper/findbugsExclude.xml  |   4 +
 8 files changed, 206 insertions(+), 19 deletions(-)

diff --git 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerHandle.java
 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerHandle.java
index ca6cb89..2207fc5 100644
--- 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerHandle.java
+++ 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerHandle.java
@@ -231,10 +231,9 @@ public class LedgerHandle implements WriteHandle {
     }
 
     /**
-     * Get the LedgerMetadata
-     *
-     * @return LedgerMetadata for the LedgerHandle
+     * {@inheritDoc}
      */
+    @Override
     public LedgerMetadata getLedgerMetadata() {
         return metadata;
     }
diff --git 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerMetadata.java
 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerMetadata.java
index 44c8ce7..180c59e 100644
--- 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerMetadata.java
+++ 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerMetadata.java
@@ -35,9 +35,11 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.NavigableMap;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import org.apache.bookkeeper.client.api.DigestType;
 import org.apache.bookkeeper.net.BookieSocketAddress;
 import org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat;
 import org.apache.bookkeeper.versioning.Version;
@@ -50,7 +52,7 @@ import org.slf4j.LoggerFactory;
  *
  * <p>It provides parsing and serialization methods of such metadata.
  */
-public class LedgerMetadata {
+public class LedgerMetadata implements 
org.apache.bookkeeper.client.api.LedgerMetadata {
     static final Logger LOG = LoggerFactory.getLogger(LedgerMetadata.class);
 
     private static final String closed = "CLOSED";
@@ -77,7 +79,7 @@ public class LedgerMetadata {
     private boolean storeSystemtimeAsLedgerCreationTime;
 
     private LedgerMetadataFormat.State state;
-    private SortedMap<Long, ArrayList<BookieSocketAddress>> ensembles =
+    private TreeMap<Long, ArrayList<BookieSocketAddress>> ensembles =
         new TreeMap<Long, ArrayList<BookieSocketAddress>>();
     ArrayList<BookieSocketAddress> currentEnsemble;
     volatile Version version = Version.NEW;
@@ -173,30 +175,35 @@ public class LedgerMetadata {
      * @return SortedMap of Ledger Fragments and the corresponding
      * bookie ensembles that store the entries.
      */
-    public SortedMap<Long, ArrayList<BookieSocketAddress>> getEnsembles() {
+    public TreeMap<Long, ArrayList<BookieSocketAddress>> getEnsembles() {
         return ensembles;
     }
 
-    void setEnsembles(SortedMap<Long, ArrayList<BookieSocketAddress>> 
ensembles) {
+    @Override
+    public NavigableMap<Long, ? extends List<BookieSocketAddress>> 
getAllEnsembles() {
+        return ensembles;
+    }
+
+    void setEnsembles(TreeMap<Long, ArrayList<BookieSocketAddress>> ensembles) 
{
         this.ensembles = ensembles;
     }
 
+    @Override
     public int getEnsembleSize() {
         return ensembleSize;
     }
 
+    @Override
     public int getWriteQuorumSize() {
         return writeQuorumSize;
     }
 
+    @Override
     public int getAckQuorumSize() {
         return ackQuorumSize;
     }
 
-    /**
-     * Get the creation timestamp of the ledger
-     * @return
-     */
+    @Override
     public long getCtime() {
         return ctime;
     }
@@ -221,18 +228,21 @@ public class LedgerMetadata {
         return Arrays.copyOf(password, password.length);
     }
 
-    BookKeeper.DigestType getDigestType() {
+    @Override
+    public DigestType getDigestType() {
         if (digestType.equals(LedgerMetadataFormat.DigestType.HMAC)) {
-            return BookKeeper.DigestType.MAC;
+            return DigestType.MAC;
         } else {
-            return BookKeeper.DigestType.CRC32;
+            return DigestType.CRC32;
         }
     }
 
+    @Override
     public long getLastEntryId() {
         return lastEntryId;
     }
 
+    @Override
     public long getLength() {
         return length;
     }
@@ -241,6 +251,7 @@ public class LedgerMetadata {
         this.length = length;
     }
 
+    @Override
     public boolean isClosed() {
         return state == LedgerMetadataFormat.State.CLOSED;
     }
@@ -279,6 +290,11 @@ public class LedgerMetadata {
         return ensembles.get(ensembles.headMap(entryId + 1).lastKey());
     }
 
+    @Override
+    public List<BookieSocketAddress> getEnsembleAt(long entryId) {
+        return getEnsemble(entryId);
+    }
+
     /**
      * the entry id greater than the given entry-id at which the next ensemble 
change takes
      * place
@@ -296,6 +312,7 @@ public class LedgerMetadata {
         }
     }
 
+    @Override
     public Map<String, byte[]> getCustomMetadata() {
         return this.customMetadata;
     }
diff --git 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerOpenOp.java
 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerOpenOp.java
index 910f33a..256cd59 100644
--- 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerOpenOp.java
+++ 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/LedgerOpenOp.java
@@ -21,6 +21,8 @@
 
 package org.apache.bookkeeper.client;
 
+import static 
org.apache.bookkeeper.client.BookKeeper.DigestType.fromApiDigestType;
+
 import java.util.Arrays;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
@@ -128,7 +130,7 @@ class LedgerOpenOp implements 
GenericCallback<LedgerMetadata> {
 
         final byte[] passwd;
         DigestType digestType = enableDigestAutodetection 
-                                    ? metadata.getDigestType() 
+                                    ? 
fromApiDigestType(metadata.getDigestType())
                                     : suggestedDigestType;
                                                                                
         /* For an administrative open, the default passwords
@@ -136,7 +138,7 @@ class LedgerOpenOp implements 
GenericCallback<LedgerMetadata> {
          * already contains passwords, use these instead. */
         if (administrativeOpen && metadata.hasPassword()) {
             passwd = metadata.getPassword();
-            digestType = metadata.getDigestType();
+            digestType = fromApiDigestType(metadata.getDigestType());
         } else {
             passwd = this.passwd;
 
@@ -146,7 +148,7 @@ class LedgerOpenOp implements 
GenericCallback<LedgerMetadata> {
                     openComplete(BKException.Code.UnauthorizedAccessException, 
null);
                     return;
                 }
-                if (digestType != metadata.getDigestType()) {
+                if (digestType != fromApiDigestType(metadata.getDigestType())) 
{
                     LOG.error("Provided digest does not match that in 
metadata");
                     openComplete(BKException.Code.DigestMatchException, null);
                     return;
@@ -276,7 +278,7 @@ class LedgerOpenOp implements 
GenericCallback<LedgerMetadata> {
                 return;
             }
 
-            LedgerOpenOp op = new LedgerOpenOp(bk, builderLedgerId, 
DigestType.fromApiDigestType(builderDigestType),
+            LedgerOpenOp op = new LedgerOpenOp(bk, builderLedgerId, 
fromApiDigestType(builderDigestType),
                 builderPassword, cb, null);
             ReentrantReadWriteLock closeLock = bk.getCloseLock();
             closeLock.readLock().lock();
diff --git 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/api/Handle.java 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/api/Handle.java
index 326f2e6..f520e61 100644
--- 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/api/Handle.java
+++ 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/api/Handle.java
@@ -56,6 +56,17 @@ public interface Handle extends AutoCloseable {
     }
 
     /**
+     * Returns the metadata of this ledger.
+     *
+     * <p>This call only retrieves the metadata cached locally. If there is 
any metadata updated, the read
+     * handle will receive the metadata updates and update the metadata 
locally. The metadata notification
+     * can be deplayed, so it is possible you can receive a stale copy of 
ledger metadata from this call.
+     *
+     * @return the metadata of this ledger.
+     */
+    LedgerMetadata getLedgerMetadata();
+
+    /**
      * Asynchronous close, any adds in flight will return errors.
      *
      * <p>Closing a ledger will ensure that all clients agree on what the last
diff --git 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/api/LedgerMetadata.java
 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/api/LedgerMetadata.java
new file mode 100644
index 0000000..dc2deb6
--- /dev/null
+++ 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/api/LedgerMetadata.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.bookkeeper.client.api;
+
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
+import 
org.apache.bookkeeper.common.annotation.InterfaceAudience.LimitedPrivate;
+import org.apache.bookkeeper.common.annotation.InterfaceStability.Unstable;
+import org.apache.bookkeeper.net.BookieSocketAddress;
+
+/**
+ * Represents the client-side metadata of a ledger. It is immutable.
+ *
+ * @since 4.6
+ */
+@LimitedPrivate
+@Unstable
+public interface LedgerMetadata {
+
+    /**
+     * Returns the ensemble size of this ledger.
+     *
+     * @return the ensemble size of this ledger.
+     */
+    int getEnsembleSize();
+
+    /**
+     * Returns the write quorum size of this ledger.
+     *
+     * @return the write quorum size of this ledger.
+     */
+    int getWriteQuorumSize();
+
+    /**
+     * Returns the ack quorum size of this ledger.
+     *
+     * @return the ack quorum size of this ledger.
+     */
+    int getAckQuorumSize();
+
+    /**
+     * Returns the last entry id of this ledger.
+     *
+     * <p>If this ledger is not sealed {@link #isClosed()}, it returns {@code 
-1L}.
+     *
+     * @return the last entry id of this ledger if it is sealed, otherwise -1.
+     */
+    long getLastEntryId();
+
+    /**
+     * Returns the length of this ledger.
+     *
+     * <p>If this ledger is not sealed {@link #isClosed()}, it returns {@code 
0}.
+     *
+     * @return the length of this ledger if it is sealed, otherwise 0.
+     */
+    long getLength();
+
+    /**
+     * Returns the digest type used by this ledger.
+     *
+     * @return the digest type used by this ledger.
+     */
+    DigestType getDigestType();
+
+    /**
+     * Returns the creation timestamp of this ledger.
+     *
+     * @return the creation timestamp of this ledger.
+     */
+    long getCtime();
+
+    /**
+     * Returns whether the ledger is sealed or not.
+     *
+     * @return true if the ledger is sealed, otherwise false.
+     */
+    boolean isClosed();
+
+    /**
+     * Returns the custom metadata stored with the ledgers.
+     *
+     * @return the custom metadata stored with the ledgers.
+     */
+    Map<String, byte[]> getCustomMetadata();
+
+    /**
+     * Returns the ensemble at the given {@code entryId}.
+     *
+     * @param entryId the entry id to retrieve its ensemble information
+     * @return the ensemble which contains the given {@code entryId}.
+     */
+    List<BookieSocketAddress> getEnsembleAt(long entryId);
+
+    /**
+     * Returns all the ensembles of this entry.
+     *
+     * @return all the ensembles of this entry.
+     */
+    NavigableMap<Long, ? extends List<BookieSocketAddress>> getAllEnsembles();
+
+
+}
diff --git 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerMetadataTest.java
 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerMetadataTest.java
index d7b913f..a58147c 100644
--- 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerMetadataTest.java
+++ 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/LedgerMetadataTest.java
@@ -20,10 +20,13 @@
 package org.apache.bookkeeper.client;
 
 import static com.google.common.base.Charsets.UTF_8;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.util.Collections;
+import java.util.NoSuchElementException;
 import org.apache.bookkeeper.client.BookKeeper.DigestType;
 import org.apache.bookkeeper.proto.DataFormats.LedgerMetadataFormat;
 import org.junit.Test;
@@ -36,6 +39,36 @@ public class LedgerMetadataTest {
     private static final byte[] passwd = "testPasswd".getBytes(UTF_8);
 
     @Test
+    public void testGetters() {
+        org.apache.bookkeeper.client.api.LedgerMetadata metadata = new 
LedgerMetadata(
+            3,
+            2,
+            1,
+            DigestType.CRC32,
+            passwd,
+            Collections.emptyMap(),
+            false);
+
+        assertEquals(3, metadata.getEnsembleSize());
+        assertEquals(2, metadata.getWriteQuorumSize());
+        assertEquals(1, metadata.getAckQuorumSize());
+        assertEquals(org.apache.bookkeeper.client.api.DigestType.CRC32, 
metadata.getDigestType());
+        assertEquals(Collections.emptyMap(), metadata.getCustomMetadata());
+        assertEquals(-1L, metadata.getCtime());
+        assertEquals(-1L, metadata.getLastEntryId());
+        assertEquals(0, metadata.getLength());
+        assertFalse(metadata.isClosed());
+        assertTrue(metadata.getAllEnsembles().isEmpty());
+
+        try {
+            metadata.getEnsembleAt(99L);
+            fail("Should fail to retrieve ensemble if ensembles is empty");
+        } catch (NoSuchElementException e) {
+            // expected
+        }
+    }
+
+    @Test
     public void testStoreSystemtimeAsLedgerCtimeEnabled()
             throws Exception {
         LedgerMetadata lm = new LedgerMetadata(
diff --git 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSequenceRead.java
 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSequenceRead.java
index 8e38487..05cf072 100644
--- 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSequenceRead.java
+++ 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestSequenceRead.java
@@ -55,7 +55,7 @@ public class TestSequenceRead extends 
BookKeeperClusterTestCase {
         final LedgerHandle lh = bkc.createLedger(3, 3, 3, digestType, passwd);
         // introduce duplicated bookies in an ensemble.
         SortedMap<Long, ArrayList<BookieSocketAddress>> ensembles = 
lh.getLedgerMetadata().getEnsembles();
-        SortedMap<Long, ArrayList<BookieSocketAddress>> newEnsembles = new 
TreeMap<Long, ArrayList<BookieSocketAddress>>();
+        TreeMap<Long, ArrayList<BookieSocketAddress>> newEnsembles = new 
TreeMap<>();
         for (Map.Entry<Long, ArrayList<BookieSocketAddress>> entry : 
ensembles.entrySet()) {
             ArrayList<BookieSocketAddress> newList = new 
ArrayList<BookieSocketAddress>(entry.getValue().size());
             BookieSocketAddress firstBookie = entry.getValue().get(0);
diff --git a/buildtools/src/main/resources/bookkeeper/findbugsExclude.xml 
b/buildtools/src/main/resources/bookkeeper/findbugsExclude.xml
index e239e67..2cc5ce7 100644
--- a/buildtools/src/main/resources/bookkeeper/findbugsExclude.xml
+++ b/buildtools/src/main/resources/bookkeeper/findbugsExclude.xml
@@ -51,6 +51,10 @@
     <Bug pattern="NM_SAME_SIMPLE_NAME_AS_INTERFACE" />
   </Match>
   <Match>
+    <Class name="org.apache.bookkeeper.client.LedgerMetadata" />
+    <Bug pattern="NM_SAME_SIMPLE_NAME_AS_INTERFACE" />
+  </Match>
+  <Match>
     <Class name="org.apache.bookkeeper.client.BookKeeper" />
     <Bug pattern="NM_SAME_SIMPLE_NAME_AS_INTERFACE" />
   </Match>

-- 
To stop receiving notification emails like this one, please contact
['"commits@bookkeeper.apache.org" <commits@bookkeeper.apache.org>'].

Reply via email to