### Question:
LongZkLedgerIdGenerator implements LedgerIdGenerator { @Override public void generateLedgerId(final GenericCallback<Long> cb) { try { if (!ledgerIdGenPathPresent(zk)) { shortIdGen.generateLedgerId(new GenericCallback<Long>(){ @Override public void operationComplete(int rc, Long result) { if (rc == BKException.Code.LedgerIdOverflowException) { createLongLedgerIdPathAndGenerateLongLedgerId(cb, ledgerIdGenPath); } else { cb.operationComplete(rc, result); } } }); } else { generateLongLedgerId(cb); } } catch (KeeperException e) { LOG.error("Failed to create long ledger ID path", e); cb.operationComplete(BKException.Code.ZKException, null); } catch (InterruptedException e) { Thread.currentThread().interrupt(); LOG.error("Failed to create long ledger ID path", e); cb.operationComplete(BKException.Code.InterruptedException, null); } catch (IOException e) { LOG.error("Failed to create long ledger ID path", e); cb.operationComplete(BKException.Code.IllegalOpException, null); } } LongZkLedgerIdGenerator(ZooKeeper zk, String ledgersPath, String idGenZnodeName,
            ZkLedgerIdGenerator shortIdGen, List<ACL> zkAcls); void invalidateLedgerIdGenPathStatus(); synchronized boolean ledgerIdGenPathPresent(ZooKeeper zk); @Override void generateLedgerId(final GenericCallback<Long> cb); @Override void close();  }### Answer:
@Test public void testGenerateLedgerId() throws Exception { final int nThread = 2; final int nLedgers = 2000; final CountDownLatch countDownLatch = new CountDownLatch(nThread * nLedgers * 2); final AtomicInteger errCount = new AtomicInteger(0); final ConcurrentLinkedQueue<Long> ledgerIds = new ConcurrentLinkedQueue<Long>(); final GenericCallback<Long> cb = new GenericCallback<Long>() { @Override public void operationComplete(int rc, Long result) { if (Code.OK.intValue() == rc) { ledgerIds.add(result); } else { errCount.incrementAndGet(); } countDownLatch.countDown(); } }; long start = System.currentTimeMillis(); for (int i = 0; i < nThread; i++) { new Thread() { @Override public void run() { for (int j = 0; j < nLedgers; j++) { ledgerIdGenerator.generateLedgerId(cb); } } }.start(); } ZkUtils.createFullPathOptimistic(zk, "/test-zk-ledger-id-generator/idgen-long", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); ledgerIdGenerator.invalidateLedgerIdGenPathStatus(); for (int i = 0; i < nThread; i++) { new Thread() { @Override public void run() { for (int j = 0; j < nLedgers; j++) { ledgerIdGenerator.generateLedgerId(cb); } } }.start(); } assertTrue("Wait ledger id generation threads to stop timeout : ", countDownLatch.await(120, TimeUnit.SECONDS)); LOG.info("Number of generated ledger id: {}, time used: {}", ledgerIds.size(), System.currentTimeMillis() - start); assertEquals("Error occur during ledger id generation : ", 0, errCount.get()); Set<Long> ledgers = new HashSet<Long>(); while (!ledgerIds.isEmpty()) { Long ledger = ledgerIds.poll(); assertNotNull("Generated ledger id is null : ", ledger); assertFalse("Ledger id [" + ledger + "] conflict : ", ledgers.contains(ledger)); ledgers.add(ledger); } }