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

reddycharan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git


The following commit(s) were added to refs/heads/master by this push:
     new 9540d84  Replicascheck comprehensive testcases.
9540d84 is described below

commit 9540d8473ebbe49425ece1088047cd544e8427f9
Author: Charan Reddy Guttapalem <[email protected]>
AuthorDate: Tue Aug 13 10:53:39 2019 -0700

    Replicascheck comprehensive testcases.
    
    
    Descriptions of the changes in this PR:
    
    - adding comprehensive testcases for newly added
    scrutiny - replicasCheck.
    
    
    Reviewers: Enrico Olivelli <[email protected]>, Sijie Guo <None>
    
    This closes #2141 from reddycharan/replicaschecktest
---
 .../org/apache/bookkeeper/replication/Auditor.java |  35 +-
 .../util/AvailabilityOfEntriesOfLedger.java        |   7 +
 .../replication/AuditorPeriodicCheckTest.java      |   6 +
 .../AuditorPlacementPolicyCheckTest.java           |   1 +
 .../replication/AuditorReplicasCheckTest.java      | 810 +++++++++++++++++++++
 5 files changed, 852 insertions(+), 7 deletions(-)

diff --git 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/replication/Auditor.java
 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/replication/Auditor.java
index 3b8219f..7e815de 100644
--- 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/replication/Auditor.java
+++ 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/replication/Auditor.java
@@ -136,7 +136,8 @@ public class Auditor implements AutoCloseable {
     private final ServerConfiguration conf;
     private final BookKeeper bkc;
     private final boolean ownBkc;
-    private BookKeeperAdmin admin;
+    private final BookKeeperAdmin admin;
+    private final boolean ownAdmin;
     private BookieLedgerIndexer bookieLedgerIndexer;
     private LedgerManager ledgerManager;
     private LedgerUnderreplicationManager ledgerUnderreplicationManager;
@@ -297,10 +298,27 @@ public class Auditor implements AutoCloseable {
     }
 
     public Auditor(final String bookieIdentifier,
-                   ServerConfiguration conf,
-                   BookKeeper bkc,
-                   boolean ownBkc,
-                   StatsLogger statsLogger)
+            ServerConfiguration conf,
+            BookKeeper bkc,
+            boolean ownBkc,
+            StatsLogger statsLogger)
+                    throws UnavailableException {
+        this(bookieIdentifier,
+                conf,
+                bkc,
+                ownBkc,
+                new BookKeeperAdmin(bkc, statsLogger),
+                true,
+                statsLogger);
+    }
+
+    public Auditor(final String bookieIdentifier,
+            ServerConfiguration conf,
+            BookKeeper bkc,
+            boolean ownBkc,
+            BookKeeperAdmin admin,
+            boolean ownAdmin,
+            StatsLogger statsLogger)
         throws UnavailableException {
         this.conf = conf;
         this.underreplicatedLedgerRecoveryGracePeriod = 
conf.getUnderreplicatedLedgerRecoveryGracePeriod();
@@ -419,6 +437,8 @@ public class Auditor implements AutoCloseable {
 
         this.bkc = bkc;
         this.ownBkc = ownBkc;
+        this.admin = admin;
+        this.ownAdmin = ownAdmin;
         initialize(conf, bkc);
 
         executor = Executors.newSingleThreadScheduledExecutor(new 
ThreadFactory() {
@@ -443,7 +463,6 @@ public class Auditor implements AutoCloseable {
 
             this.ledgerUnderreplicationManager = ledgerManagerFactory
                     .newLedgerUnderreplicationManager();
-            this.admin = new BookKeeperAdmin(bkc, statsLogger);
             LOG.info("AuthProvider used by the Auditor is {}",
                 admin.getConf().getClientAuthProviderFactoryClass());
             if (this.ledgerUnderreplicationManager
@@ -1910,7 +1929,9 @@ public class Auditor implements AutoCloseable {
                 LOG.warn("Executor not shutting down, interrupting");
                 executor.shutdownNow();
             }
-            admin.close();
+            if (ownAdmin) {
+                admin.close();
+            }
             if (ownBkc) {
                 bkc.close();
             }
diff --git 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/util/AvailabilityOfEntriesOfLedger.java
 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/util/AvailabilityOfEntriesOfLedger.java
index b4987c8..4695d8c 100644
--- 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/util/AvailabilityOfEntriesOfLedger.java
+++ 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/util/AvailabilityOfEntriesOfLedger.java
@@ -184,6 +184,13 @@ public class AvailabilityOfEntriesOfLedger {
         this.closeStateOfEntriesOfALedger();
     }
 
+    public AvailabilityOfEntriesOfLedger(long[] entriesOfLedger) {
+        for (long entry : entriesOfLedger) {
+            this.addEntryToAvailabileEntriesOfLedger(entry);
+        }
+        this.closeStateOfEntriesOfALedger();
+    }
+
     public AvailabilityOfEntriesOfLedger(byte[] 
serializeStateOfEntriesOfLedger) {
         byte[] header = new byte[HEADER_SIZE];
         byte[] serializedSequenceGroupByteArray = new 
byte[SequenceGroup.SEQUENCEGROUP_BYTES];
diff --git 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicCheckTest.java
 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicCheckTest.java
index 3999c3c..448913e 100644
--- 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicCheckTest.java
+++ 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPeriodicCheckTest.java
@@ -54,6 +54,7 @@ import org.apache.bookkeeper.client.AsyncCallback.AddCallback;
 import org.apache.bookkeeper.client.BKException;
 import org.apache.bookkeeper.client.BookKeeper;
 import org.apache.bookkeeper.client.BookKeeper.DigestType;
+import org.apache.bookkeeper.client.BookKeeperAdmin;
 import org.apache.bookkeeper.client.LedgerHandle;
 import org.apache.bookkeeper.conf.ServerConfiguration;
 import org.apache.bookkeeper.meta.LedgerManagerFactory;
@@ -663,6 +664,11 @@ public class AuditorPeriodicCheckTest extends 
BookKeeperClusterTestCase {
             super(bookieIdentifier, conf, bkc, ownBkc, statsLogger);
         }
 
+        public TestAuditor(String bookieIdentifier, ServerConfiguration conf, 
BookKeeper bkc, boolean ownBkc,
+                BookKeeperAdmin bkadmin, boolean ownadmin, StatsLogger 
statsLogger) throws UnavailableException {
+            super(bookieIdentifier, conf, bkc, ownBkc, bkadmin, ownadmin, 
statsLogger);
+        }
+
         public TestAuditor(final String bookieIdentifier, ServerConfiguration 
conf, StatsLogger statsLogger)
                 throws UnavailableException {
             super(bookieIdentifier, conf, statsLogger);
diff --git 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPlacementPolicyCheckTest.java
 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPlacementPolicyCheckTest.java
index b8548e0..468a032 100644
--- 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPlacementPolicyCheckTest.java
+++ 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorPlacementPolicyCheckTest.java
@@ -656,6 +656,7 @@ public class AuditorPlacementPolicyCheckTest extends 
BookKeeperClusterTestCase {
         servConf.setProperty(ClientConfiguration.ENSEMBLE_PLACEMENT_POLICY, 
ensemblePlacementPolicyClass);
         servConf.setAuditorPeriodicCheckInterval(0);
         servConf.setAuditorPeriodicBookieCheckInterval(0);
+        servConf.setAuditorPeriodicReplicasCheckInterval(0);
         servConf.setAuditorPeriodicPlacementPolicyCheckInterval(1000);
     }
 
diff --git 
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorReplicasCheckTest.java
 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorReplicasCheckTest.java
new file mode 100644
index 0000000..a2d5f6b
--- /dev/null
+++ 
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/replication/AuditorReplicasCheckTest.java
@@ -0,0 +1,810 @@
+/**
+ *
+ * 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.replication;
+
+import static org.apache.bookkeeper.replication.ReplicationStats.AUDITOR_SCOPE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.net.URI;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.bookkeeper.bookie.Bookie;
+import org.apache.bookkeeper.bookie.BookieException;
+import org.apache.bookkeeper.client.BKException;
+import org.apache.bookkeeper.client.BookKeeper;
+import org.apache.bookkeeper.client.BookKeeperAdmin;
+import org.apache.bookkeeper.client.LedgerMetadataBuilder;
+import org.apache.bookkeeper.client.api.DigestType;
+import org.apache.bookkeeper.client.api.LedgerMetadata;
+import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.discover.RegistrationManager;
+import org.apache.bookkeeper.meta.LedgerManager;
+import org.apache.bookkeeper.meta.LedgerManagerFactory;
+import org.apache.bookkeeper.meta.LedgerUnderreplicationManager;
+import org.apache.bookkeeper.meta.MetadataBookieDriver;
+import org.apache.bookkeeper.meta.MetadataDrivers;
+import org.apache.bookkeeper.meta.exceptions.MetadataException;
+import org.apache.bookkeeper.net.BookieSocketAddress;
+import org.apache.bookkeeper.replication.AuditorPeriodicCheckTest.TestAuditor;
+import 
org.apache.bookkeeper.replication.ReplicationException.CompatibilityException;
+import 
org.apache.bookkeeper.replication.ReplicationException.UnavailableException;
+import org.apache.bookkeeper.stats.Gauge;
+import org.apache.bookkeeper.stats.NullStatsLogger;
+import org.apache.bookkeeper.stats.StatsLogger;
+import org.apache.bookkeeper.test.BookKeeperClusterTestCase;
+import org.apache.bookkeeper.test.TestStatsProvider;
+import org.apache.bookkeeper.test.TestStatsProvider.TestOpStatsLogger;
+import org.apache.bookkeeper.test.TestStatsProvider.TestStatsLogger;
+import org.apache.bookkeeper.util.AvailabilityOfEntriesOfLedger;
+import org.apache.bookkeeper.util.StaticDNSResolver;
+import org.apache.commons.collections4.map.MultiKeyMap;
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.apache.zookeeper.KeeperException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests the logic of Auditor's ReplicasCheck.
+ */
+public class AuditorReplicasCheckTest extends BookKeeperClusterTestCase {
+    private MetadataBookieDriver driver;
+
+    public AuditorReplicasCheckTest() {
+        super(1);
+        baseConf.setPageLimit(1); // to make it easy to push ledger out of 
cache
+    }
+
+    @Before
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        StaticDNSResolver.reset();
+        driver = 
MetadataDrivers.getBookieDriver(URI.create(bsConfs.get(0).getMetadataServiceUri()));
+        driver.initialize(bsConfs.get(0), () -> {
+        }, NullStatsLogger.INSTANCE);
+    }
+
+    @After
+    @Override
+    public void tearDown() throws Exception {
+        if (null != driver) {
+            driver.close();
+        }
+        super.tearDown();
+    }
+
+    private class TestBookKeeperAdmin extends BookKeeperAdmin {
+
+        private final MultiKeyMap<String, AvailabilityOfEntriesOfLedger> 
returnAvailabilityOfEntriesOfLedger;
+        private final MultiKeyMap<String, Integer> 
errorReturnValueForGetAvailabilityOfEntriesOfLedger;
+
+        public TestBookKeeperAdmin(BookKeeper bkc, StatsLogger statsLogger,
+                MultiKeyMap<String, AvailabilityOfEntriesOfLedger> 
returnAvailabilityOfEntriesOfLedger,
+                MultiKeyMap<String, Integer> 
errorReturnValueForGetAvailabilityOfEntriesOfLedger) {
+            super(bkc, statsLogger);
+            this.returnAvailabilityOfEntriesOfLedger = 
returnAvailabilityOfEntriesOfLedger;
+            this.errorReturnValueForGetAvailabilityOfEntriesOfLedger =
+                    errorReturnValueForGetAvailabilityOfEntriesOfLedger;
+        }
+
+        @Override
+        public CompletableFuture<AvailabilityOfEntriesOfLedger> 
asyncGetListOfEntriesOfLedger(
+                BookieSocketAddress address, long ledgerId) {
+            CompletableFuture<AvailabilityOfEntriesOfLedger> futureResult =
+                    new CompletableFuture<AvailabilityOfEntriesOfLedger>();
+            Integer errorReturnValue = 
errorReturnValueForGetAvailabilityOfEntriesOfLedger.get(address.toString(),
+                    Long.toString(ledgerId));
+            if (errorReturnValue != null) {
+                
futureResult.completeExceptionally(BKException.create(errorReturnValue).fillInStackTrace());
+            } else {
+                AvailabilityOfEntriesOfLedger availabilityOfEntriesOfLedger = 
returnAvailabilityOfEntriesOfLedger
+                        .get(address.toString(), Long.toString(ledgerId));
+                futureResult.complete(availabilityOfEntriesOfLedger);
+            }
+            return futureResult;
+        }
+    }
+
+    private TestStatsLogger 
startAuditorAndWaitForReplicasCheck(ServerConfiguration servConf,
+            MutableObject<Auditor> auditorRef,
+            MultiKeyMap<String, AvailabilityOfEntriesOfLedger> 
expectedReturnAvailabilityOfEntriesOfLedger,
+            MultiKeyMap<String, Integer> 
errorReturnValueForGetAvailabilityOfEntriesOfLedger)
+            throws MetadataException, CompatibilityException, KeeperException, 
InterruptedException,
+            UnavailableException, UnknownHostException {
+        LedgerManagerFactory mFactory = driver.getLedgerManagerFactory();
+        LedgerUnderreplicationManager urm = 
mFactory.newLedgerUnderreplicationManager();
+        TestStatsProvider statsProvider = new TestStatsProvider();
+        TestStatsLogger statsLogger = 
statsProvider.getStatsLogger(AUDITOR_SCOPE);
+        TestOpStatsLogger replicasCheckStatsLogger = (TestOpStatsLogger) 
statsLogger
+                .getOpStatsLogger(ReplicationStats.REPLICAS_CHECK_TIME);
+
+        final TestAuditor auditor = new 
TestAuditor(Bookie.getBookieAddress(servConf).toString(), servConf, bkc, true,
+                new TestBookKeeperAdmin(bkc, statsLogger, 
expectedReturnAvailabilityOfEntriesOfLedger,
+                        errorReturnValueForGetAvailabilityOfEntriesOfLedger),
+                true, statsLogger);
+        auditorRef.setValue(auditor);
+        CountDownLatch latch = auditor.getLatch();
+        assertEquals("REPLICAS_CHECK_TIME SuccessCount", 0, 
replicasCheckStatsLogger.getSuccessCount());
+        urm.setReplicasCheckCTime(-1);
+        auditor.start();
+        /*
+         * since replicasCheckCTime is set to -1, replicasCheck should be
+         * scheduled to run with no initialdelay
+         */
+        assertTrue("replicasCheck should have executed", latch.await(20, 
TimeUnit.SECONDS));
+        for (int i = 0; i < 200; i++) {
+            Thread.sleep(100);
+            if (replicasCheckStatsLogger.getSuccessCount() >= 1) {
+                break;
+            }
+        }
+        assertEquals("REPLICAS_CHECK_TIME SuccessCount", 1, 
replicasCheckStatsLogger.getSuccessCount());
+        return statsLogger;
+    }
+
+    private void setServerConfigProperties(ServerConfiguration servConf) {
+        servConf.setAuditorPeriodicCheckInterval(0);
+        servConf.setAuditorPeriodicBookieCheckInterval(0);
+        servConf.setAuditorPeriodicPlacementPolicyCheckInterval(0);
+        servConf.setAuditorPeriodicReplicasCheckInterval(1000);
+    }
+
+    List<BookieSocketAddress> addAndRegisterBookies(RegistrationManager 
regManager, int numOfBookies)
+            throws BookieException {
+        BookieSocketAddress bookieAddress;
+        List<BookieSocketAddress> bookieAddresses = new 
ArrayList<BookieSocketAddress>();
+        for (int i = 0; i < numOfBookies; i++) {
+            bookieAddress = new BookieSocketAddress("98.98.98." + i, 2181);
+            bookieAddresses.add(bookieAddress);
+            regManager.registerBookie(bookieAddress.toString(), false);
+        }
+        return bookieAddresses;
+    }
+
+    private void createClosedLedgerMetadata(LedgerManager lm, long ledgerId, 
int ensembleSize, int writeQuorumSize,
+            int ackQuorumSize, Map<Long, List<BookieSocketAddress>> 
segmentEnsembles, long lastEntryId, int length,
+            DigestType digestType, byte[] password) throws 
InterruptedException, ExecutionException {
+        LedgerMetadataBuilder ledgerMetadataBuilder = 
LedgerMetadataBuilder.create();
+        
ledgerMetadataBuilder.withEnsembleSize(ensembleSize).withWriteQuorumSize(writeQuorumSize)
+                
.withAckQuorumSize(ackQuorumSize).withClosedState().withLastEntryId(lastEntryId).withLength(length)
+                .withDigestType(digestType).withPassword(password);
+        for (Map.Entry<Long, List<BookieSocketAddress>> mapEntry : 
segmentEnsembles.entrySet()) {
+            ledgerMetadataBuilder.newEnsembleEntry(mapEntry.getKey(), 
mapEntry.getValue());
+        }
+        LedgerMetadata initMeta = ledgerMetadataBuilder.build();
+        lm.createLedgerMetadata(ledgerId, initMeta).get();
+    }
+
+    private void createNonClosedLedgerMetadata(LedgerManager lm, long 
ledgerId, int ensembleSize, int writeQuorumSize,
+            int ackQuorumSize, Map<Long, List<BookieSocketAddress>> 
segmentEnsembles, DigestType digestType,
+            byte[] password) throws InterruptedException, ExecutionException {
+        LedgerMetadataBuilder ledgerMetadataBuilder = 
LedgerMetadataBuilder.create();
+        
ledgerMetadataBuilder.withEnsembleSize(ensembleSize).withWriteQuorumSize(writeQuorumSize)
+                
.withAckQuorumSize(ackQuorumSize).withDigestType(digestType).withPassword(password);
+        for (Map.Entry<Long, List<BookieSocketAddress>> mapEntry : 
segmentEnsembles.entrySet()) {
+            ledgerMetadataBuilder.newEnsembleEntry(mapEntry.getKey(), 
mapEntry.getValue());
+        }
+        LedgerMetadata initMeta = ledgerMetadataBuilder.build();
+        lm.createLedgerMetadata(ledgerId, initMeta).get();
+    }
+
+    private void runTestScenario(MultiKeyMap<String, 
AvailabilityOfEntriesOfLedger> returnAvailabilityOfEntriesOfLedger,
+            MultiKeyMap<String, Integer> 
errorReturnValueForGetAvailabilityOfEntriesOfLedger,
+            int expectedNumLedgersFoundHavingNoReplicaOfAnEntry,
+            int expectedNumLedgersHavingLessThanAQReplicasOfAnEntry,
+            int expectedNumLedgersHavingLessThanWQReplicasOfAnEntry) throws 
CompatibilityException,
+            UnavailableException, UnknownHostException, MetadataException, 
KeeperException, InterruptedException {
+        ServerConfiguration servConf = new ServerConfiguration(bsConfs.get(0));
+        setServerConfigProperties(servConf);
+        MutableObject<Auditor> auditorRef = new MutableObject<Auditor>();
+        try {
+            TestStatsLogger statsLogger = 
startAuditorAndWaitForReplicasCheck(servConf, auditorRef,
+                    returnAvailabilityOfEntriesOfLedger, 
errorReturnValueForGetAvailabilityOfEntriesOfLedger);
+            checkReplicasCheckStats(statsLogger, 
expectedNumLedgersFoundHavingNoReplicaOfAnEntry,
+                    expectedNumLedgersHavingLessThanAQReplicasOfAnEntry,
+                    expectedNumLedgersHavingLessThanWQReplicasOfAnEntry);
+        } finally {
+            Auditor auditor = auditorRef.getValue();
+            if (auditor != null) {
+                auditor.close();
+            }
+        }
+    }
+
+    private void checkReplicasCheckStats(TestStatsLogger statsLogger,
+            int expectedNumLedgersFoundHavingNoReplicaOfAnEntry,
+            int expectedNumLedgersHavingLessThanAQReplicasOfAnEntry,
+            int expectedNumLedgersHavingLessThanWQReplicasOfAnEntry) {
+        Gauge<? extends Number> numLedgersFoundHavingNoReplicaOfAnEntryGuage = 
statsLogger
+                
.getGauge(ReplicationStats.NUM_LEDGERS_HAVING_NO_REPLICA_OF_AN_ENTRY);
+        Gauge<? extends Number> 
numLedgersHavingLessThanAQReplicasOfAnEntryGuage = statsLogger
+                
.getGauge(ReplicationStats.NUM_LEDGERS_HAVING_LESS_THAN_AQ_REPLICAS_OF_AN_ENTRY);
+        Gauge<? extends Number> 
numLedgersHavingLessThanWQReplicasOfAnEntryGuage = statsLogger
+                
.getGauge(ReplicationStats.NUM_LEDGERS_HAVING_LESS_THAN_WQ_REPLICAS_OF_AN_ENTRY);
+
+        assertEquals("NUM_LEDGERS_HAVING_NO_REPLICA_OF_AN_ENTRY guage value",
+                expectedNumLedgersFoundHavingNoReplicaOfAnEntry,
+                numLedgersFoundHavingNoReplicaOfAnEntryGuage.getSample());
+        assertEquals("NUM_LEDGERS_HAVING_LESS_THAN_AQ_REPLICAS_OF_AN_ENTRY 
guage value",
+                expectedNumLedgersHavingLessThanAQReplicasOfAnEntry,
+                numLedgersHavingLessThanAQReplicasOfAnEntryGuage.getSample());
+        assertEquals("NUM_LEDGERS_HAVING_LESS_THAN_WQ_REPLICAS_OF_AN_ENTRY 
guage value",
+                expectedNumLedgersHavingLessThanWQReplicasOfAnEntry,
+                numLedgersHavingLessThanWQReplicasOfAnEntryGuage.getSample());
+    }
+
+    /*
+     * For all the ledgers and for all the bookies,
+     * asyncGetListOfEntriesOfLedger would return
+     * BookieHandleNotAvailableException, so these ledgers wouldn't be counted
+     * against expectedNumLedgersFoundHavingNoReplicaOfAnEntry /
+     * LessThanAQReplicasOfAnEntry / LessThanWQReplicasOfAnEntry.
+     */
+    @Test
+    public void testReplicasCheckForBookieHandleNotAvailable() throws 
Exception {
+        int numOfBookies = 5;
+        RegistrationManager regManager = driver.getRegistrationManager();
+        MultiKeyMap<String, AvailabilityOfEntriesOfLedger> 
returnAvailabilityOfEntriesOfLedger =
+                new MultiKeyMap<String, AvailabilityOfEntriesOfLedger>();
+        MultiKeyMap<String, Integer> 
errorReturnValueForGetAvailabilityOfEntriesOfLedger =
+                new MultiKeyMap<String, Integer>();
+        List<BookieSocketAddress> bookieAddresses = 
addAndRegisterBookies(regManager, numOfBookies);
+
+        LedgerManagerFactory mFactory = driver.getLedgerManagerFactory();
+        LedgerManager lm = mFactory.newLedgerManager();
+        int ensembleSize = 5;
+        int writeQuorumSize = 4;
+        int ackQuorumSize = 2;
+        long lastEntryId = 100;
+        int length = 10000;
+        DigestType digestType = DigestType.DUMMY;
+        byte[] password = new byte[0];
+        Collections.shuffle(bookieAddresses);
+
+        /*
+         * closed ledger
+         *
+         * for this ledger, for all the bookies we are setting
+         * errorReturnValueForGetAvailabilityOfEntriesOfLedger to
+         * BookieHandleNotAvailableException so asyncGetListOfEntriesOfLedger 
will
+         * return BookieHandleNotAvailableException.
+         */
+        Map<Long, List<BookieSocketAddress>> segmentEnsembles = new 
HashMap<Long, List<BookieSocketAddress>>();
+        segmentEnsembles.put(0L, bookieAddresses);
+        long ledgerId = 1L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        for (BookieSocketAddress bookieSocketAddress : bookieAddresses) {
+            
errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(),
+                    Long.toString(ledgerId), 
BKException.Code.BookieHandleNotAvailableException);
+        }
+
+        ensembleSize = 4;
+        /*
+         * closed ledger with multiple segments
+         *
+         * for this ledger, for all the bookies we are setting
+         * errorReturnValueForGetAvailabilityOfEntriesOfLedger to
+         * BookieHandleNotAvailableException so asyncGetListOfEntriesOfLedger 
will
+         * return BookieHandleNotAvailableException.
+         */
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        segmentEnsembles.put(20L, bookieAddresses.subList(1, 5));
+        segmentEnsembles.put(60L, bookieAddresses.subList(0, 4));
+        ledgerId = 2L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        for (BookieSocketAddress bookieSocketAddress : bookieAddresses) {
+            
errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(),
+                    Long.toString(ledgerId), 
BKException.Code.BookieHandleNotAvailableException);
+        }
+
+        /*
+         * non-closed ledger
+         */
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        ledgerId = 3L;
+        createNonClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                digestType, password);
+        for (BookieSocketAddress bookieSocketAddress : bookieAddresses) {
+            
errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(),
+                    Long.toString(ledgerId), 
BKException.Code.BookieHandleNotAvailableException);
+        }
+
+        /*
+         * non-closed ledger with multiple segments
+         *
+         */
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        segmentEnsembles.put(20L, bookieAddresses.subList(1, 5));
+        segmentEnsembles.put(60L, bookieAddresses.subList(0, 4));
+        ledgerId = 4L;
+        createNonClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                digestType, password);
+        for (BookieSocketAddress bookieSocketAddress : bookieAddresses) {
+            
errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(),
+                    Long.toString(ledgerId), 
BKException.Code.BookieHandleNotAvailableException);
+        }
+
+        runTestScenario(returnAvailabilityOfEntriesOfLedger, 
errorReturnValueForGetAvailabilityOfEntriesOfLedger, 0, 0,
+                0);
+    }
+
+    /*
+     * In this testscenario all the ledgers have a missing entry. So all closed
+     * ledgers should be counted towards
+     * numLedgersFoundHavingNoReplicaOfAnEntry.
+     */
+    @Test
+    public void testReplicasCheckForLedgersFoundHavingNoReplica() throws 
Exception {
+        int numOfBookies = 5;
+        RegistrationManager regManager = driver.getRegistrationManager();
+        MultiKeyMap<String, AvailabilityOfEntriesOfLedger> 
returnAvailabilityOfEntriesOfLedger =
+                new MultiKeyMap<String, AvailabilityOfEntriesOfLedger>();
+        MultiKeyMap<String, Integer> 
errorReturnValueForGetAvailabilityOfEntriesOfLedger =
+                new MultiKeyMap<String, Integer>();
+        List<BookieSocketAddress> bookieAddresses = 
addAndRegisterBookies(regManager, numOfBookies);
+
+        LedgerManagerFactory mFactory = driver.getLedgerManagerFactory();
+        LedgerManager lm = mFactory.newLedgerManager();
+        int ensembleSize = 5;
+        int writeQuorumSize = 4;
+        int ackQuorumSize = 2;
+        long lastEntryId = 100;
+        int length = 10000;
+        DigestType digestType = DigestType.DUMMY;
+        byte[] password = new byte[0];
+        Collections.shuffle(bookieAddresses);
+
+        int numLedgersFoundHavingNoReplicaOfAnEntry = 0;
+
+        /*
+         * closed ledger
+         *
+         * for this ledger we are setting returnAvailabilityOfEntriesOfLedger 
to
+         * Empty one for all of the bookies, so this ledger would be counted in
+         * ledgersFoundHavingNoReplicaOfAnEntry .
+         */
+        Map<Long, List<BookieSocketAddress>> segmentEnsembles = new 
HashMap<Long, List<BookieSocketAddress>>();
+        segmentEnsembles.put(0L, bookieAddresses);
+        long ledgerId = 1L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        for (BookieSocketAddress bookieSocketAddress : bookieAddresses) {
+            
returnAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(), 
Long.toString(ledgerId),
+                    
AvailabilityOfEntriesOfLedger.EMPTY_AVAILABILITYOFENTRIESOFLEDGER);
+        }
+        numLedgersFoundHavingNoReplicaOfAnEntry++;
+
+        ensembleSize = 4;
+        /*
+         * closed ledger with multiple segments
+         *
+         * for this ledger we are setting
+         * errorReturnValueForGetAvailabilityOfEntriesOfLedger to
+         * NoSuchLedgerExistsException. This is equivalent to
+         * EMPTY_AVAILABILITYOFENTRIESOFLEDGER. So this ledger would be counted
+         * in ledgersFoundHavingNoReplicaOfAnEntry
+         */
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        segmentEnsembles.put(20L, bookieAddresses.subList(1, 5));
+        segmentEnsembles.put(60L, bookieAddresses.subList(0, 4));
+        ledgerId = 2L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        for (BookieSocketAddress bookieSocketAddress : bookieAddresses) {
+            
errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(),
+                    Long.toString(ledgerId), 
BKException.Code.NoSuchLedgerExistsException);
+        }
+        numLedgersFoundHavingNoReplicaOfAnEntry++;
+
+        /*
+         * non-closed ledger
+         *
+         * since this is non-closed ledger, it should not be counted in
+         * ledgersFoundHavingNoReplicaOfAnEntry
+         */
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        ledgerId = 3L;
+        createNonClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                digestType, password);
+        for (BookieSocketAddress bookieSocketAddress : bookieAddresses) {
+            
returnAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(), 
Long.toString(ledgerId),
+                    
AvailabilityOfEntriesOfLedger.EMPTY_AVAILABILITYOFENTRIESOFLEDGER);
+        }
+
+        ensembleSize = 3;
+        writeQuorumSize = 3;
+        ackQuorumSize = 2;
+        lastEntryId = 1;
+        length = 1000;
+        /*
+         * closed ledger
+         *
+         * for this ledger we are setting returnAvailabilityOfEntriesOfLedger 
to
+         * just {0l} for all of the bookies and entry 1l is missing for all of
+         * the bookies, so this ledger would be counted in
+         * ledgersFoundHavingNoReplicaOfAnEntry
+         */
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 3));
+        ledgerId = 4L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        for (BookieSocketAddress bookieSocketAddress : bookieAddresses) {
+            
returnAvailabilityOfEntriesOfLedger.put(bookieSocketAddress.toString(), 
Long.toString(ledgerId),
+                    new AvailabilityOfEntriesOfLedger(new long[] { 0L }));
+        }
+        numLedgersFoundHavingNoReplicaOfAnEntry++;
+
+        /*
+         * For this closed ledger, entry 1 is missing. So it should be counted
+         * towards numLedgersFoundHavingNoReplicaOfAnEntry.
+         */
+        ensembleSize = 4;
+        writeQuorumSize = 3;
+        ackQuorumSize = 2;
+        lastEntryId = 3;
+        length = 10000;
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        ledgerId = 5L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 2, 3 }));
+        numLedgersFoundHavingNoReplicaOfAnEntry++;
+
+        runTestScenario(returnAvailabilityOfEntriesOfLedger, 
errorReturnValueForGetAvailabilityOfEntriesOfLedger,
+                numLedgersFoundHavingNoReplicaOfAnEntry, 0, 0);
+    }
+
+    /*
+     * In this testscenario all the ledgers have an entry with less than AQ
+     * number of copies. So all closed ledgers should be counted towards
+     * numLedgersFoundHavingLessThanAQReplicasOfAnEntry.
+     */
+    @Test
+    public void 
testReplicasCheckForLedgersFoundHavingLessThanAQReplicasOfAnEntry() throws 
Exception {
+        int numOfBookies = 5;
+        RegistrationManager regManager = driver.getRegistrationManager();
+        MultiKeyMap<String, AvailabilityOfEntriesOfLedger> 
returnAvailabilityOfEntriesOfLedger =
+                new MultiKeyMap<String, AvailabilityOfEntriesOfLedger>();
+        MultiKeyMap<String, Integer> 
errorReturnValueForGetAvailabilityOfEntriesOfLedger =
+                new MultiKeyMap<String, Integer>();
+        List<BookieSocketAddress> bookieAddresses = 
addAndRegisterBookies(regManager, numOfBookies);
+
+        LedgerManagerFactory mFactory = driver.getLedgerManagerFactory();
+        LedgerManager lm = mFactory.newLedgerManager();
+        DigestType digestType = DigestType.DUMMY;
+        byte[] password = new byte[0];
+        Collections.shuffle(bookieAddresses);
+
+        int numLedgersFoundHavingLessThanAQReplicasOfAnEntry = 0;
+
+        /*
+         * closed ledger
+         *
+         * for this ledger there is only one copy of entry 2, so this ledger
+         * would be counted towards
+         * ledgersFoundHavingLessThanAQReplicasOfAnEntry.
+         */
+        Map<Long, List<BookieSocketAddress>> segmentEnsembles = new 
HashMap<Long, List<BookieSocketAddress>>();
+        int ensembleSize = 4;
+        int writeQuorumSize = 3;
+        int ackQuorumSize = 2;
+        long lastEntryId = 3;
+        int length = 10000;
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        long ledgerId = 1L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 1, 2, 3 }));
+        numLedgersFoundHavingLessThanAQReplicasOfAnEntry++;
+
+        /*
+         * closed ledger with multiple segments.
+         *
+         * for this ledger there is only one copy of entry 2, so this ledger
+         * would be counted towards
+         * ledgersFoundHavingLessThanAQReplicasOfAnEntry.
+         *
+         */
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        segmentEnsembles.put(2L, bookieAddresses.subList(1, 5));
+        ledgerId = 2L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] {}));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 1 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(4).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 3 }));
+        numLedgersFoundHavingLessThanAQReplicasOfAnEntry++;
+
+        /*
+         * closed ledger with multiple segments
+         *
+         * for this ledger entry 2 is overrreplicated, but it has only one copy
+         * in the set of bookies it is supposed to be. So it should be counted
+         * towards ledgersFoundHavingLessThanAQReplicasOfAnEntry.
+         */
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        segmentEnsembles.put(2L, bookieAddresses.subList(1, 5));
+        ledgerId = 3L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 2 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 1 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(4).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 3 }));
+        numLedgersFoundHavingLessThanAQReplicasOfAnEntry++;
+
+        /*
+         * non-closed ledger
+         *
+         * since this is non-closed ledger, it should not be counted towards
+         * ledgersFoundHavingLessThanAQReplicasOfAnEntry
+         */
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        segmentEnsembles.put(2L, bookieAddresses.subList(1, 5));
+        ledgerId = 4L;
+        createNonClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                digestType, password);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] {}));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 1 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(4).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 3 }));
+
+        /*
+         * this is closed ledger.
+         *
+         * For third bookie, asyncGetListOfEntriesOfLedger will fail with
+         * BookieHandleNotAvailableException, so this should not be counted
+         * against missing copies of an entry. Other than that, for both 
entries
+         * 0 and 1, two copies are missing. Hence this should be counted 
towards
+         * numLedgersFoundHavingLessThanAQReplicasOfAnEntry.
+         */
+        ensembleSize = 3;
+        writeQuorumSize = 3;
+        ackQuorumSize = 2;
+        lastEntryId = 1;
+        length = 1000;
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 3));
+        ledgerId = 5L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), 
Long.toString(ledgerId),
+                
AvailabilityOfEntriesOfLedger.EMPTY_AVAILABILITYOFENTRIESOFLEDGER);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), 
Long.toString(ledgerId),
+                
AvailabilityOfEntriesOfLedger.EMPTY_AVAILABILITYOFENTRIESOFLEDGER);
+        
errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(),
+                    Long.toString(ledgerId), 
BKException.Code.BookieHandleNotAvailableException);
+        numLedgersFoundHavingLessThanAQReplicasOfAnEntry++;
+
+        runTestScenario(returnAvailabilityOfEntriesOfLedger, 
errorReturnValueForGetAvailabilityOfEntriesOfLedger, 0,
+                numLedgersFoundHavingLessThanAQReplicasOfAnEntry, 0);
+    }
+
+    /*
+     * In this testscenario all the ledgers have an entry with less than WQ
+     * number of copies but greater than AQ. So all closed ledgers should be
+     * counted towards numLedgersFoundHavingLessThanWQReplicasOfAnEntry.
+     */
+    @Test
+    public void 
testReplicasCheckForLedgersFoundHavingLessThanWQReplicasOfAnEntry() throws 
Exception {
+        int numOfBookies = 5;
+        RegistrationManager regManager = driver.getRegistrationManager();
+        MultiKeyMap<String, AvailabilityOfEntriesOfLedger> 
returnAvailabilityOfEntriesOfLedger =
+                new MultiKeyMap<String, AvailabilityOfEntriesOfLedger>();
+        MultiKeyMap<String, Integer> 
errorReturnValueForGetAvailabilityOfEntriesOfLedger =
+                new MultiKeyMap<String, Integer>();
+        List<BookieSocketAddress> bookieAddresses = 
addAndRegisterBookies(regManager, numOfBookies);
+
+        LedgerManagerFactory mFactory = driver.getLedgerManagerFactory();
+        LedgerManager lm = mFactory.newLedgerManager();
+        DigestType digestType = DigestType.DUMMY;
+        byte[] password = new byte[0];
+        Collections.shuffle(bookieAddresses);
+
+        int numLedgersFoundHavingLessThanWQReplicasOfAnEntry = 0;
+
+        /*
+         * closed ledger
+         *
+         * for this ledger a copy of entry 3, so this ledger would be counted
+         * towards ledgersFoundHavingLessThanWQReplicasOfAnEntry.
+         */
+        Map<Long, List<BookieSocketAddress>> segmentEnsembles = new 
HashMap<Long, List<BookieSocketAddress>>();
+        int ensembleSize = 4;
+        int writeQuorumSize = 3;
+        int ackQuorumSize = 2;
+        long lastEntryId = 3;
+        int length = 10000;
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        long ledgerId = 1L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 2 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 1, 2, 3 }));
+        numLedgersFoundHavingLessThanWQReplicasOfAnEntry++;
+
+        /*
+         * closed ledger with multiple segments
+         *
+         * for this ledger a copy of entry 0 and entry 2 are missing, so this
+         * ledger would be counted towards
+         * ledgersFoundHavingLessThanWQReplicasOfAnEntry.
+         */
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        segmentEnsembles.put(2L, bookieAddresses.subList(1, 5));
+        ledgerId = 2L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] {}));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 1 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(4).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 2, 3 }));
+        numLedgersFoundHavingLessThanWQReplicasOfAnEntry++;
+
+        /*
+         * non-closed ledger with multiple segments
+         *
+         * since this is non-closed ledger, it should not be counted towards
+         * ledgersFoundHavingLessThanWQReplicasOfAnEntry
+         */
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        segmentEnsembles.put(2L, bookieAddresses.subList(1, 5));
+        ledgerId = 3L;
+        createNonClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                digestType, password);
+        
errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(),
+                Long.toString(ledgerId), 
BKException.Code.NoSuchLedgerExistsException);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 1 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(4).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 2, 3 }));
+
+        /*
+         * closed ledger.
+         *
+         * for this ledger entry 0 is overrreplicated, but a copy is missing in
+         * the set of bookies it is supposed to be. So it should be counted
+         * towards ledgersFoundHavingLessThanWQReplicasOfAnEntry.
+         */
+        ensembleSize = 4;
+        writeQuorumSize = 3;
+        ackQuorumSize = 2;
+        lastEntryId = 1;
+        length = 1000;
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 4));
+        ledgerId = 4L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1, 2, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 1, 3 }));
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(3).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0 }));
+        numLedgersFoundHavingLessThanWQReplicasOfAnEntry++;
+
+        /*
+         * this is closed ledger.
+         *
+         * For third bookie, asyncGetListOfEntriesOfLedger will fail with
+         * BookieHandleNotAvailableException, so this should not be counted
+         * against missing copies of an entry. Other than that, for both 
entries
+         * 0 and 1, a copy is missing. Hence this should be counted towards
+         * numLedgersFoundHavingLessThanWQReplicasOfAnEntry.
+         */
+        ensembleSize = 3;
+        writeQuorumSize = 3;
+        ackQuorumSize = 2;
+        lastEntryId = 1;
+        length = 1000;
+        segmentEnsembles.clear();
+        segmentEnsembles.put(0L, bookieAddresses.subList(0, 3));
+        ledgerId = 5L;
+        createClosedLedgerMetadata(lm, ledgerId, ensembleSize, 
writeQuorumSize, ackQuorumSize, segmentEnsembles,
+                lastEntryId, length, digestType, password);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(0).toString(), 
Long.toString(ledgerId),
+                
AvailabilityOfEntriesOfLedger.EMPTY_AVAILABILITYOFENTRIESOFLEDGER);
+        
returnAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(1).toString(), 
Long.toString(ledgerId),
+                new AvailabilityOfEntriesOfLedger(new long[] { 0, 1 }));
+        
errorReturnValueForGetAvailabilityOfEntriesOfLedger.put(bookieAddresses.get(2).toString(),
+                Long.toString(ledgerId), 
BKException.Code.BookieHandleNotAvailableException);
+        numLedgersFoundHavingLessThanWQReplicasOfAnEntry++;
+
+        runTestScenario(returnAvailabilityOfEntriesOfLedger, 
errorReturnValueForGetAvailabilityOfEntriesOfLedger, 0, 0,
+                numLedgersFoundHavingLessThanWQReplicasOfAnEntry);
+    }
+}

Reply via email to