/**
   * Tests that Replication worker should clean the leadger under replication node of the ledger
   * already deleted
   */
  @Test(timeout = 3000)
  public void testRWShouldCleanTheLedgerFromUnderReplicationIfLedgerAlreadyDeleted()
      throws Exception {
    LedgerHandle lh = bkc.createLedger(2, 2, BookKeeper.DigestType.CRC32, TESTPASSWD);

    for (int i = 0; i < 10; i++) {
      lh.addEntry(data);
    }
    lh.close();
    BookieSocketAddress replicaToKill =
        LedgerHandleAdapter.getLedgerMetadata(lh).getEnsembles().get(0L).get(0);
    LOG.info("Killing Bookie", replicaToKill);
    killBookie(replicaToKill);

    int startNewBookie = startNewBookie();
    BookieSocketAddress newBkAddr =
        new BookieSocketAddress(InetAddress.getLocalHost().getHostAddress(), startNewBookie);
    LOG.info("New Bookie addr :" + newBkAddr);
    ReplicationWorker rw = new ReplicationWorker(zkc, baseConf, newBkAddr);
    rw.start();

    try {
      bkc.deleteLedger(lh.getId()); // Deleting the ledger
      // Also mark ledger as in UnderReplication
      underReplicationManager.markLedgerUnderreplicated(lh.getId(), replicaToKill.toString());
      while (isLedgerInUnderReplication(lh.getId(), basePath)) {
        Thread.sleep(100);
      }
    } finally {
      rw.shutdown();
    }
  }
  @Test(timeout = 60000)
  public void testAllocation() throws Exception {
    String allocationPath = "/allocation1";
    SimpleLedgerAllocator allocator = createAllocator(allocationPath);
    allocator.allocate();
    ZKTransaction txn = newTxn();
    LedgerHandle lh = FutureUtils.result(allocator.tryObtain(txn, NULL_LISTENER));
    logger.info("Try obtaining ledger handle {}", lh.getId());
    byte[] data = zkc.get().getData(allocationPath, false, null);
    assertEquals((Long) lh.getId(), Long.valueOf(new String(data, UTF_8)));
    txn.addOp(DefaultZKOp.of(Op.setData("/unexistedpath", "data".getBytes(UTF_8), -1)));
    try {
      FutureUtils.result(txn.execute());
      fail("Should fail the transaction when setting unexisted path");
    } catch (ZKException ke) {
      // expected
      logger.info("Should fail on executing transaction when setting unexisted path", ke);
    }
    data = zkc.get().getData(allocationPath, false, null);
    assertEquals((Long) lh.getId(), Long.valueOf(new String(data, UTF_8)));

    // Create new transaction to obtain the ledger again.
    txn = newTxn();
    // we could obtain the ledger if it was obtained
    LedgerHandle newLh = FutureUtils.result(allocator.tryObtain(txn, NULL_LISTENER));
    assertEquals(lh.getId(), newLh.getId());
    FutureUtils.result(txn.execute());
    data = zkc.get().getData(allocationPath, false, null);
    assertEquals(0, data.length);
    Utils.close(allocator);
  }
  private void internalReadFromLedger(LedgerHandle ledger, OpReadEntry opReadEntry) {
    // Perform the read
    long firstEntry = opReadEntry.readPosition.getEntryId();

    if (firstEntry > ledger.getLastAddConfirmed()) {
      log.debug(
          "[{}] No more messages to read from ledger={} lastEntry={} readEntry={}",
          va(name, ledger.getId(), ledger.getLastAddConfirmed(), firstEntry));

      if (ledger.getId() != currentLedger.getId()) {
        // Cursor was placed past the end of one ledger, move it to the
        // beginning of the next ledger
        Long nextLedgerId = ledgers.ceilingKey(ledger.getId() + 1);
        opReadEntry.nextReadPosition = new Position(nextLedgerId, 0);
      }

      opReadEntry.emptyResponse();
      return;
    }

    long lastEntry = min(firstEntry + opReadEntry.count - 1, ledger.getLastAddConfirmed());

    long expectedEntries = lastEntry - firstEntry + 1;
    opReadEntry.entries = Lists.newArrayListWithExpectedSize((int) expectedEntries);

    log.debug(
        "[{}] Reading entries from ledger {} - first={} last={}",
        va(name, ledger.getId(), firstEntry, lastEntry));
    ledger.asyncReadEntries(firstEntry, lastEntry, this, opReadEntry);
  }
 @After
 public void tearDown() throws Exception {
   if (createdLedgers != null && bookKeeperClient != null) {
     for (LedgerHandle ledger : createdLedgers) {
       LOG.info("Deleting ledger with id " + ledger.getId());
       bookKeeperClient.deleteLedger(ledger.getId());
     }
   }
 }
  /**
   * Tests that replication worker1 should take one fragment replication and other replication
   * worker also should compete for the replication.
   */
  @Test(timeout = 90000)
  public void test2RWsShouldCompeteForReplicationOf2FragmentsAndCompleteReplication()
      throws Exception {
    LedgerHandle lh = bkc.createLedger(2, 2, BookKeeper.DigestType.CRC32, TESTPASSWD);

    for (int i = 0; i < 10; i++) {
      lh.addEntry(data);
    }
    lh.close();
    BookieSocketAddress replicaToKill =
        LedgerHandleAdapter.getLedgerMetadata(lh).getEnsembles().get(0L).get(0);
    LOG.info("Killing Bookie", replicaToKill);
    ServerConfiguration killedBookieConfig = killBookie(replicaToKill);

    killAllBookies(lh, null);
    // Starte RW1
    int startNewBookie1 = startNewBookie();
    BookieSocketAddress newBkAddr1 =
        new BookieSocketAddress(InetAddress.getLocalHost().getHostAddress(), startNewBookie1);
    LOG.info("New Bookie addr :" + newBkAddr1);
    ReplicationWorker rw1 = new ReplicationWorker(zkc, baseConf, newBkAddr1);

    // Starte RW2
    int startNewBookie2 = startNewBookie();
    BookieSocketAddress newBkAddr2 =
        new BookieSocketAddress(InetAddress.getLocalHost().getHostAddress(), startNewBookie2);
    LOG.info("New Bookie addr :" + newBkAddr2);
    ZooKeeper zkc1 =
        ZooKeeperClient.createConnectedZooKeeperClient(zkUtil.getZooKeeperConnectString(), 10000);
    ReplicationWorker rw2 = new ReplicationWorker(zkc1, baseConf, newBkAddr2);
    rw1.start();
    rw2.start();

    try {
      underReplicationManager.markLedgerUnderreplicated(lh.getId(), replicaToKill.toString());
      int counter = 10;
      while (counter-- > 0) {
        assertTrue(
            "Expecting that replication should not complete",
            isLedgerInUnderReplication(lh.getId(), basePath));
        Thread.sleep(100);
      }
      // restart killed bookie
      bs.add(startBookie(killedBookieConfig));
      bsConfs.add(killedBookieConfig);
      while (isLedgerInUnderReplication(lh.getId(), basePath)) {
        Thread.sleep(100);
      }
      // Should be able to read the entries from 0-9
      verifyRecoveredLedgers(lh, 0, 9);
    } finally {
      rw1.shutdown();
      rw2.shutdown();
      zkc1.close();
    }
  }
  /**
   * Tests that ReplicationWorker should not have identified for postponing the replication if
   * ledger is in open state and lastFragment is not in underReplication state. Note that RW should
   * not fence such ledgers.
   */
  @Test(timeout = 30000)
  public void testRWShouldReplicateTheLedgersAfterTimeoutIfLastFragmentIsNotUR() throws Exception {
    LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, TESTPASSWD);

    for (int i = 0; i < 10; i++) {
      lh.addEntry(data);
    }
    BookieSocketAddress replicaToKill =
        LedgerHandleAdapter.getLedgerMetadata(lh).getEnsembles().get(0L).get(0);

    LOG.info("Killing Bookie", replicaToKill);
    killBookie(replicaToKill);

    int startNewBookie = startNewBookie();

    // Reform ensemble...Making sure that last fragment is not in
    // under-replication
    for (int i = 0; i < 10; i++) {
      lh.addEntry(data);
    }

    BookieSocketAddress newBkAddr =
        new BookieSocketAddress(InetAddress.getLocalHost().getHostAddress(), startNewBookie);
    LOG.info("New Bookie addr :" + newBkAddr);

    ReplicationWorker rw = new ReplicationWorker(zkc, baseConf, newBkAddr);

    LedgerManagerFactory mFactory =
        LedgerManagerFactory.newLedgerManagerFactory(baseClientConf, zkc);
    LedgerUnderreplicationManager underReplicationManager =
        mFactory.newLedgerUnderreplicationManager();

    rw.start();
    try {

      underReplicationManager.markLedgerUnderreplicated(lh.getId(), replicaToKill.toString());
      while (isLedgerInUnderReplication(lh.getId(), basePath)) {
        Thread.sleep(100);
      }

      killAllBookies(lh, newBkAddr);

      // Should be able to read the entries from 0-9
      verifyRecoveredLedgers(lh, 0, 9);
      lh = bkc.openLedgerNoRecovery(lh.getId(), BookKeeper.DigestType.CRC32, TESTPASSWD);

      // Ledger should be still in open state
      assertTrue("Ledger must have been closed by RW", ClientUtil.isLedgerOpen(lh));
    } finally {
      rw.shutdown();
      underReplicationManager.close();
    }
  }
  protected synchronized boolean hasMoreEntries(Position position) {
    if (position.getLedgerId() == currentLedger.getId()) {
      // If we are reading from the last ledger, use the
      // LedgerHandle metadata
      return position.getEntryId() <= currentLedger.getLastAddConfirmed();
    } else if (currentLedger.getLastAddConfirmed() >= 0) {
      // We have entries in the current ledger and we are reading from an
      // older ledger
      return true;
    } else {
      // At this point, currentLedger is empty, we need to check in the
      // older ledgers for entries past the current position
      LedgerStat ls = ledgers.get(position.getLedgerId());
      if (ls == null) {
        // The cursor haven't been initialized yet
        checkArgument(position.getLedgerId() == -1);
        return true;
      } else if (position.getEntryId() < ls.getEntriesCount()) {
        // There are still entries to read in the current reading ledger
        return true;
      } else {
        for (LedgerStat stat : ledgers.tailMap(position.getLedgerId(), false).values()) {
          if (stat.getEntriesCount() > 0) return true;
        }

        return false;
      }
    }
  }
  /*
   * (non-Javadoc)
   *
   * @see
   * org.apache.bookkeeper.mledger.impl.MetaStore.UpdateLedgersIdsCallback
   * #updateLedgersIdsComplete
   * (org.apache.bookkeeper.mledger.ManagedLedgerException.MetaStoreException)
   */
  public synchronized void updateLedgersIdsComplete(Version version) {
    state = State.LedgerOpened;
    ledgersVersion = version;

    // Process all the pending addEntry requests
    while (!pendingAddEntries.isEmpty()) {
      OpAddEntry op = pendingAddEntries.poll();

      op.setLedger(currentLedger);
      ++currentLedgerEntries;
      currentLedgerSize += op.data.length;

      if (currentLedgerIsFull()) {
        state = State.ClosingLedger;
        op.setCloseWhenDone(true);
        op.initiate();
        log.debug(
            "[{}] Stop writing into ledger {} queue={}",
            va(name, currentLedger.getId(), pendingAddEntries.size()));
        break;
      } else {
        op.initiate();
      }
    }
  }
  /**
   * Skip a specified number of entries and return the resulting position.
   *
   * @param startPosition the current position
   * @param entriesToSkip the numbers of entries to skip
   * @return the new position
   */
  protected synchronized Position skipEntries(Position startPosition, int entriesToSkip) {
    log.debug("[{}] Skipping {} entries from position {}", va(name, entriesToSkip, startPosition));
    long ledgerId = startPosition.getLedgerId();
    entriesToSkip += startPosition.getEntryId();

    while (entriesToSkip > 0) {
      if (currentLedger != null && ledgerId == currentLedger.getId()) {
        checkArgument(entriesToSkip <= (currentLedger.getLastAddConfirmed() + 1));
        return new Position(ledgerId, entriesToSkip);
      } else {
        LedgerStat ledger = ledgers.get(ledgerId);
        if (ledger == null) {
          checkArgument(!ledgers.isEmpty());
          ledgerId = ledgers.ceilingKey(ledgerId);
          continue;
        }

        if (entriesToSkip < ledger.getEntriesCount()) {
          return new Position(ledgerId, entriesToSkip);
        } else {
          // Move to next ledger
          entriesToSkip -= ledger.getEntriesCount();
          ledgerId = ledgers.ceilingKey(ledgerId + 1);
        }
      }
    }

    return new Position(ledgerId, 0);
  }
 @Test(timeout = 60000)
 public void testCloseAllocatorDuringObtaining() throws Exception {
   String allocationPath = "/allocation2";
   SimpleLedgerAllocator allocator = createAllocator(allocationPath);
   allocator.allocate();
   ZKTransaction txn = newTxn();
   // close during obtaining ledger.
   LedgerHandle lh = FutureUtils.result(allocator.tryObtain(txn, NULL_LISTENER));
   Utils.close(allocator);
   byte[] data = zkc.get().getData(allocationPath, false, null);
   assertEquals((Long) lh.getId(), Long.valueOf(new String(data, UTF_8)));
   // the ledger is not deleted
   bkc.get()
       .openLedger(
           lh.getId(), BookKeeper.DigestType.CRC32, dlConf.getBKDigestPW().getBytes(UTF_8));
 }
Esempio n. 11
0
  /**
   * Verify read last confirmed op, it shouldn't cause any deadlock as new bookie connection is
   * being established and returning the connection notification in the same caller thread. It would
   * be simulated by delaying the future.addlistener() in PerChannelBookieClient after the
   * connection establishment. Now the future.addlistener() will notify back in the same thread and
   * simultaneously invoke the pendingOp.operationComplete() event.
   *
   * <p>BOOKKEEPER-326
   */
  @Test(timeout = 60000)
  public void testReadLastConfirmedOp() throws Exception {
    startNewBookie();
    startNewBookie();
    // Create a ledger
    LedgerHandle beforelh =
        bkc.createLedger(numBookies + 2, numBookies + 2, digestType, "".getBytes());

    int numEntries = 10;
    String tmp = "BookKeeper is cool!";
    for (int i = 0; i < numEntries; i++) {
      beforelh.addEntry(tmp.getBytes());
    }

    // shutdown first bookie server
    killBookie(0);
    startNewBookie();

    // create new bookie client, and forcing to establish new
    // PerChannelBookieClient connections for recovery flows.
    BookKeeperTestClient bkc1 = new BookKeeperTestClient(baseClientConf);
    // try to open ledger with recovery
    LedgerHandle afterlh = bkc1.openLedger(beforelh.getId(), digestType, "".getBytes());

    assertEquals("Entries got missed", beforelh.getLastAddPushed(), afterlh.getLastAddConfirmed());
    bkc1.close();
  }
Esempio n. 12
0
  public void testReadWriteZero() throws IOException {
    try {
      // Create a BookKeeper client and a ledger
      bkc = new BookKeeper("127.0.0.1");
      lh = bkc.createLedger(ledgerPassword);
      bkc.initMessageDigest("SHA1");
      ledgerId = lh.getId();
      LOG.info("Ledger ID: " + lh.getId());
      for (int i = 0; i < numEntriesToWrite; i++) {
        bkc.addEntry(lh, new byte[0]);
      }

      /*
       * Write a non-zero entry
       */
      ByteBuffer entry = ByteBuffer.allocate(4);
      entry.putInt(rng.nextInt(maxInt));
      entry.position(0);
      entries.add(entry.array());
      bkc.addEntry(lh, entry.array());

      bkc.closeLedger(lh);
      lh = bkc.openLedger(ledgerId, ledgerPassword);
      LOG.debug("Number of entries written: " + lh.getLast());
      assertTrue("Verifying number of entries written", lh.getLast() == (numEntriesToWrite + 1));

      ls = bkc.readEntries(lh, 0, numEntriesToWrite - 1);
      int i = 0;
      while (ls.hasMoreElements()) {
        ByteBuffer result = ByteBuffer.wrap(ls.nextElement().getEntry());
        LOG.debug("Length of result: " + result.capacity());

        assertTrue("Checking if entry " + i + " has zero bytes", result.capacity() == 0);
      }
      bkc.closeLedger(lh);
    } catch (KeeperException e) {
      e.printStackTrace();
    } catch (BKException e) {
      e.printStackTrace();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    }
  }
Esempio n. 13
0
  public void testReadWriteSyncSingleClient() throws IOException {
    try {
      // Create a BookKeeper client and a ledger
      bkc = new BookKeeper("127.0.0.1");
      lh = bkc.createLedger(ledgerPassword);
      bkc.initMessageDigest("SHA1");
      ledgerId = lh.getId();
      LOG.info("Ledger ID: " + lh.getId());
      for (int i = 0; i < numEntriesToWrite; i++) {
        ByteBuffer entry = ByteBuffer.allocate(4);
        entry.putInt(rng.nextInt(maxInt));
        entry.position(0);
        entries.add(entry.array());
        bkc.addEntry(lh, entry.array());
      }
      bkc.closeLedger(lh);
      lh = bkc.openLedger(ledgerId, ledgerPassword);
      LOG.debug("Number of entries written: " + lh.getLast());
      assertTrue("Verifying number of entries written", lh.getLast() == numEntriesToWrite);

      ls = bkc.readEntries(lh, 0, numEntriesToWrite - 1);
      int i = 0;
      while (ls.hasMoreElements()) {
        ByteBuffer origbb = ByteBuffer.wrap(entries.get(i++));
        Integer origEntry = origbb.getInt();
        ByteBuffer result = ByteBuffer.wrap(ls.nextElement().getEntry());
        LOG.debug("Length of result: " + result.capacity());
        LOG.debug("Original entry: " + origEntry);

        Integer retrEntry = result.getInt();
        LOG.debug("Retrieved entry: " + retrEntry);
        assertTrue("Checking entry " + i + " for equality", origEntry.equals(retrEntry));
      }
      bkc.closeLedger(lh);
    } catch (KeeperException e) {
      e.printStackTrace();
    } catch (BKException e) {
      e.printStackTrace();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    }
  }
  /**
   * Tests that replication worker should retry for replication until enough bookies available for
   * replication
   */
  @Test(timeout = 60000)
  public void testRWShouldRetryUntilThereAreEnoughBksAvailableForReplication() throws Exception {
    LedgerHandle lh = bkc.createLedger(1, 1, BookKeeper.DigestType.CRC32, TESTPASSWD);

    for (int i = 0; i < 10; i++) {
      lh.addEntry(data);
    }
    lh.close();
    BookieSocketAddress replicaToKill =
        LedgerHandleAdapter.getLedgerMetadata(lh).getEnsembles().get(0L).get(0);
    LOG.info("Killing Bookie", replicaToKill);
    ServerConfiguration killedBookieConfig = killBookie(replicaToKill);

    int startNewBookie = startNewBookie();
    BookieSocketAddress newBkAddr =
        new BookieSocketAddress(InetAddress.getLocalHost().getHostAddress(), startNewBookie);
    LOG.info("New Bookie addr :" + newBkAddr);

    killAllBookies(lh, newBkAddr);
    ReplicationWorker rw = new ReplicationWorker(zkc, baseConf, newBkAddr);

    rw.start();
    try {
      underReplicationManager.markLedgerUnderreplicated(lh.getId(), replicaToKill.toString());
      int counter = 100;
      while (counter-- > 0) {
        assertTrue(
            "Expecting that replication should not complete",
            isLedgerInUnderReplication(lh.getId(), basePath));
        Thread.sleep(100);
      }
      // restart killed bookie
      bs.add(startBookie(killedBookieConfig));
      bsConfs.add(killedBookieConfig);
      while (isLedgerInUnderReplication(lh.getId(), basePath)) {
        Thread.sleep(100);
      }
      // Should be able to read the entries from 0-9
      verifyRecoveredLedgers(lh, 0, 9);
    } finally {
      rw.shutdown();
    }
  }
  /**
   * Validate whether a specified position is valid for the current managed ledger.
   *
   * @param position the position to validate
   * @return true if the position is valid, false otherwise
   */
  protected synchronized boolean isValidPosition(Position position) {
    if (position.getLedgerId() == currentLedger.getId()) {
      return position.getEntryId() <= currentLedger.getLastAddConfirmed();
    } else {
      // Look in the ledgers map
      LedgerStat ls = ledgers.get(position.getLedgerId());
      if (ls == null) return false;

      return position.getEntryId() < ls.getEntriesCount();
    }
  }
 private void verifyRecoveredLedgers(LedgerHandle lh, long startEntryId, long endEntryId)
     throws BKException, InterruptedException {
   LedgerHandle lhs =
       bkc.openLedgerNoRecovery(lh.getId(), BookKeeper.DigestType.CRC32, TESTPASSWD);
   Enumeration<LedgerEntry> entries = lhs.readEntries(startEntryId, endEntryId);
   assertTrue("Should have the elements", entries.hasMoreElements());
   while (entries.hasMoreElements()) {
     LedgerEntry entry = entries.nextElement();
     assertEquals("TestReplicationWorker", new String(entry.getEntry()));
   }
 }
  /**
   * Tests that replication worker should replicate the failed bookie fragments to target bookie
   * given to the worker.
   */
  @Test(timeout = 30000)
  public void testRWShouldReplicateFragmentsToTargetBookie() throws Exception {
    LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, TESTPASSWD);

    for (int i = 0; i < 10; i++) {
      lh.addEntry(data);
    }
    BookieSocketAddress replicaToKill =
        LedgerHandleAdapter.getLedgerMetadata(lh).getEnsembles().get(0L).get(0);

    LOG.info("Killing Bookie", replicaToKill);
    killBookie(replicaToKill);

    int startNewBookie = startNewBookie();
    for (int i = 0; i < 10; i++) {
      lh.addEntry(data);
    }

    BookieSocketAddress newBkAddr =
        new BookieSocketAddress(InetAddress.getLocalHost().getHostAddress(), startNewBookie);
    LOG.info("New Bookie addr :" + newBkAddr);

    ReplicationWorker rw = new ReplicationWorker(zkc, baseConf, newBkAddr);

    rw.start();
    try {

      underReplicationManager.markLedgerUnderreplicated(lh.getId(), replicaToKill.toString());

      while (isLedgerInUnderReplication(lh.getId(), basePath)) {
        Thread.sleep(100);
      }

      killAllBookies(lh, newBkAddr);

      // Should be able to read the entries from 0-9
      verifyRecoveredLedgers(lh, 0, 9);
    } finally {
      rw.shutdown();
    }
  }
  /*
   * (non-Javadoc)
   *
   * @see
   * org.apache.bookkeeper.client.AsyncCallback.OpenCallback#openComplete(int,
   * org.apache.bookkeeper.client.LedgerHandle, java.lang.Object)
   */
  @Override
  public void openComplete(int rc, LedgerHandle ledger, Object ctx) {
    OpReadEntry opReadEntry = (OpReadEntry) ctx;

    if (rc != BKException.Code.OK) {
      opReadEntry.failed(new ManagedLedgerException(BKException.create(rc)));
      return;
    }

    log.debug("[{}] Successfully opened ledger {} for reading", name, ledger.getId());
    internalReadFromLedger(ledger, opReadEntry);
  }
  /**
   * Test that if the local bookie turns out to be readonly, then no point in running RW. So RW
   * should shutdown.
   */
  @Test(timeout = 20000)
  public void testRWShutdownOnLocalBookieReadonlyTransition() throws Exception {
    LedgerHandle lh = bkc.createLedger(3, 3, BookKeeper.DigestType.CRC32, TESTPASSWD);

    for (int i = 0; i < 10; i++) {
      lh.addEntry(data);
    }
    BookieSocketAddress replicaToKill =
        LedgerHandleAdapter.getLedgerMetadata(lh).getEnsembles().get(0L).get(0);

    LOG.info("Killing Bookie", replicaToKill);
    killBookie(replicaToKill);

    int newBkPort = startNewBookie();
    for (int i = 0; i < 10; i++) {
      lh.addEntry(data);
    }

    BookieSocketAddress newBkAddr =
        new BookieSocketAddress(InetAddress.getLocalHost().getHostAddress(), newBkPort);
    LOG.info("New Bookie addr :" + newBkAddr);

    ReplicationWorker rw = new ReplicationWorker(zkc, baseConf, newBkAddr);

    rw.start();
    try {
      BookieServer newBk = bs.get(bs.size() - 1);
      bsConfs.get(bsConfs.size() - 1).setReadOnlyModeEnabled(true);
      newBk.getBookie().doTransitionToReadOnlyMode();
      underReplicationManager.markLedgerUnderreplicated(lh.getId(), replicaToKill.toString());
      while (ReplicationTestUtil.isLedgerInUnderReplication(zkc, lh.getId(), basePath)
          && rw.isRunning()) {
        Thread.sleep(100);
      }
      assertFalse("RW should shutdown if the bookie is readonly", rw.isRunning());
    } finally {
      rw.shutdown();
    }
  }
Esempio n. 20
0
 /**
  * Open a read-only LedgerHandle for reading log in no recovery mode from start entry
  *
  * @return
  * @throws BKException
  * @throws InterruptedException
  */
 public synchronized LedgerCursor getCursor(long startEntry)
     throws BKException, InterruptedException {
   if (closed) {
     LedgerHandle lh =
         bookKeeper.openLedgerNoRecovery(
             handle.getId(), DigestType.CRC32, conf.getPassword().getBytes());
     long last = lh.getLastAddConfirmed();
     return new LedgerCursor(startEntry, last, conf.getCursorBatchSize(), lh);
   } else {
     return new LedgerCursor(
         startEntry, this.handle.getLastAddConfirmed(), conf.getCursorBatchSize(), handle);
   }
 }
 @Test(timeout = 60000)
 public void testCloseAllocatorAfterAbort() throws Exception {
   String allocationPath = "/allocation3";
   SimpleLedgerAllocator allocator = createAllocator(allocationPath);
   allocator.allocate();
   ZKTransaction txn = newTxn();
   // close during obtaining ledger.
   LedgerHandle lh = FutureUtils.result(allocator.tryObtain(txn, NULL_LISTENER));
   txn.addOp(DefaultZKOp.of(Op.setData("/unexistedpath", "data".getBytes(UTF_8), -1)));
   try {
     FutureUtils.result(txn.execute());
     fail("Should fail the transaction when setting unexisted path");
   } catch (ZKException ke) {
     // expected
   }
   Utils.close(allocator);
   byte[] data = zkc.get().getData(allocationPath, false, null);
   assertEquals((Long) lh.getId(), Long.valueOf(new String(data, UTF_8)));
   // the ledger is not deleted.
   bkc.get()
       .openLedger(
           lh.getId(), BookKeeper.DigestType.CRC32, dlConf.getBKDigestPW().getBytes(UTF_8));
 }
 /**
  * Creates a new BookKeeper ledger
  *
  * @return The newly BookKeeper ledger
  * @throws IOException If unable to create the ledger
  */
 public final LedgerHandle createLedger() throws IOException {
   try {
     LedgerHandle ledger =
         bookKeeperClient.createLedger(ENSEMBLE_SIZE, QUORUM_SIZE, DigestType.MAC, LEDGER_PW);
     createdLedgers.add(ledger);
     LOG.info("Created a new ledger with id " + ledger.getId());
     return ledger;
   } catch (InterruptedException e) {
     Thread.currentThread().interrupt();
     throw new IOException("Interrupted creating the ledger", e);
   } catch (BKException e) {
     throw new IOException("Unrecoverable BookKeeper error", e);
   }
 }
Esempio n. 23
0
  @Test(timeout = 60000)
  public void testLedgerOpenAfterBKCrashed() throws Exception {
    // Create a ledger
    LedgerHandle beforelh = bkc.createLedger(numBookies, numBookies, digestType, "".getBytes());

    int numEntries = 10;
    String tmp = "BookKeeper is cool!";
    for (int i = 0; i < numEntries; i++) {
      beforelh.addEntry(tmp.getBytes());
    }

    // shutdown first bookie server
    killBookie(0);
    startNewBookie();

    // try to open ledger no recovery
    LedgerHandle afterlh = bkc.openLedger(beforelh.getId(), digestType, "".getBytes());

    assertEquals(beforelh.getLastAddPushed(), afterlh.getLastAddConfirmed());

    LedgerHandle beforelh2 = bkc.createLedger(numBookies, 1, digestType, "".getBytes());

    for (int i = 0; i < numEntries; i++) {
      beforelh2.addEntry(tmp.getBytes());
    }

    // shutdown first bookie server
    killBookie(0);

    // try to open ledger no recovery
    try {
      bkc.openLedger(beforelh2.getId(), digestType, "".getBytes());
      fail("Should have thrown exception");
    } catch (BKException.BKLedgerRecoveryException e) {
      // correct behaviour
    }
  }
  /*
   * (non-Javadoc)
   *
   * @see
   * org.apache.bookkeeper.client.AsyncCallback.ReadCallback#readComplete(int,
   * org.apache.bookkeeper.client.LedgerHandle, java.util.Enumeration,
   * java.lang.Object)
   */
  @Override
  public void readComplete(
      int rc, LedgerHandle lh, Enumeration<LedgerEntry> entriesEnum, Object ctx) {
    OpReadEntry opReadEntry = (OpReadEntry) ctx;

    if (rc != BKException.Code.OK) {
      log.warn(
          "[{}] read failed from ledger {} at position:{}",
          va(name, lh.getId(), opReadEntry.readPosition));
      opReadEntry.failed(new ManagedLedgerException(BKException.create(rc)));
      return;
    }

    List<Entry> entries = opReadEntry.entries;
    while (entriesEnum.hasMoreElements()) entries.add(new EntryImpl(entriesEnum.nextElement()));

    long lastEntry = entries.get(entries.size() - 1).getPosition().getEntryId();

    // Get the "next read position", we need to advance the position taking
    // care of ledgers boundaries
    Position nextReadPosition;
    if (lastEntry < lh.getLastAddConfirmed()) {
      nextReadPosition = new Position(lh.getId(), lastEntry + 1);
    } else {
      // Move to next ledger
      Long nextLedgerId = ledgers.ceilingKey(lh.getId() + 1);
      if (nextLedgerId == null) {
        // We are already in the last ledger
        nextReadPosition = new Position(lh.getId(), lastEntry + 1);
      } else {
        nextReadPosition = new Position(nextLedgerId, 0);
      }
    }

    opReadEntry.nextReadPosition = nextReadPosition;
    opReadEntry.succeeded();
  }
  protected synchronized void ledgerClosed(LedgerHandle lh) {
    checkArgument(lh.getId() == currentLedger.getId());
    state = State.ClosedLedger;

    log.debug(
        "[{}] Ledger has been closed id={} entries={}",
        va(name, lh.getId(), lh.getLastAddConfirmed() + 1));
    ledgers.put(lh.getId(), new LedgerStat(lh));

    trimConsumedLedgersInBackground();

    if (!pendingAddEntries.isEmpty()) {
      // Need to create a new ledger to write pending entries
      log.debug("[{}] Creating a new ledger", name);
      state = State.CreatingLedger;
      bookKeeper.asyncCreateLedger(
          config.getEnsembleSize(),
          config.getQuorumSize(),
          config.getDigestType(),
          config.getPassword(),
          this,
          null);
    }
  }
  /*
   * (non-Javadoc)
   *
   * @see
   * org.apache.bookkeeper.client.AsyncCallback.CreateCallback#createComplete
   * (int, org.apache.bookkeeper.client.LedgerHandle, java.lang.Object)
   */
  @Override
  public synchronized void createComplete(int rc, LedgerHandle lh, Object ctx) {
    log.debug("[{}] createComplete rc={} ledger={}", va(name, rc, lh != null ? lh.getId() : -1));

    if (rc != BKException.Code.OK) {
      state = State.ClosedLedger;
      log.error("[{}] Error creating ledger rc={} {}", va(name, rc, BKException.getMessage(rc)));
      ManagedLedgerException status = new ManagedLedgerException(BKException.create(rc));

      // Empty the list of pending requests and make all of them fail
      while (!pendingAddEntries.isEmpty()) {
        pendingAddEntries.poll().failed(status);
      }
    } else {
      log.debug("[{}] Successfully created new ledger {}", name, lh.getId());
      ledgers.put(lh.getId(), new LedgerStat(lh.getId(), 0, 0));
      currentLedger = lh;
      currentLedgerEntries = 0;
      currentLedgerSize = 0;

      MetaStoreCallback<Void> cb =
          new MetaStoreCallback<Void>() {
            public void operationComplete(Void v, Version version) {
              updateLedgersIdsComplete(version);
            }

            public void operationFailed(MetaStoreException e) {
              log.warn("Error updating meta data with the new list of ledgers");
              while (!pendingAddEntries.isEmpty()) {
                pendingAddEntries.poll().failed(e);
              }
            }
          };
      store.asyncUpdateLedgerIds(name, ledgers.values(), ledgersVersion, cb);
    }
  }
  @Override
  public synchronized void asyncAddEntry(
      final byte[] data, final AddEntryCallback callback, final Object ctx) {
    checkArgument(state != State.None);
    log.debug("[{}] asyncAddEntry size={} state={}", va(name, data.length, state));
    if (state == State.Fenced) {
      callback.addComplete(new ManagedLedgerFencedException(), null, ctx);
      return;
    }

    OpAddEntry addOperation = new OpAddEntry(this, data, callback, ctx);

    if (state == State.ClosingLedger || state == State.CreatingLedger) {
      // We don't have a ready ledger to write into
      // We are waiting for a new ledger to be created
      log.debug("[{}] Queue addEntry request", name);
      pendingAddEntries.add(addOperation);
    } else if (state == State.ClosedLedger) {
      // No ledger and no pending operations. Create a new one
      pendingAddEntries.add(addOperation);
      log.debug("[{}] Creating a new ledger", name);
      state = State.CreatingLedger;
      bookKeeper.asyncCreateLedger(
          config.getEnsembleSize(),
          config.getQuorumSize(),
          config.getDigestType(),
          config.getPassword(),
          this,
          ctx);
    } else {
      checkArgument(state == State.LedgerOpened);
      checkArgument(!currentLedgerIsFull());

      // Write into lastLedger
      log.debug("[{}] Write into current ledger lh={}", name, currentLedger.getId());
      addOperation.setLedger(currentLedger);

      ++currentLedgerEntries;
      currentLedgerSize += data.length;
      if (currentLedgerIsFull()) {
        // This entry will be the last added to current ledger
        addOperation.setCloseWhenDone(true);
        state = State.ClosingLedger;
      }

      addOperation.initiate();
    }
  }
  @Test(timeout = 60000)
  public void testBadVersionOnTwoAllocators() throws Exception {
    String allocationPath = "/allocation-bad-version";
    zkc.get()
        .create(allocationPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    Stat stat = new Stat();
    byte[] data = zkc.get().getData(allocationPath, false, stat);
    Versioned<byte[]> allocationData =
        new Versioned<byte[]>(data, new ZkVersion(stat.getVersion()));

    SimpleLedgerAllocator allocator1 =
        new SimpleLedgerAllocator(
            allocationPath, allocationData, newQuorumConfigProvider(dlConf), zkc, bkc);
    SimpleLedgerAllocator allocator2 =
        new SimpleLedgerAllocator(
            allocationPath, allocationData, newQuorumConfigProvider(dlConf), zkc, bkc);
    allocator1.allocate();
    // wait until allocated
    ZKTransaction txn1 = newTxn();
    LedgerHandle lh = FutureUtils.result(allocator1.tryObtain(txn1, NULL_LISTENER));
    allocator2.allocate();
    ZKTransaction txn2 = newTxn();
    try {
      FutureUtils.result(allocator2.tryObtain(txn2, NULL_LISTENER));
      fail(
          "Should fail allocating on second allocator as allocator1 is starting allocating something.");
    } catch (ZKException zke) {
      assertEquals(KeeperException.Code.BADVERSION, zke.getKeeperExceptionCode());
    }
    FutureUtils.result(txn1.execute());
    Utils.close(allocator1);
    Utils.close(allocator2);

    long eid = lh.addEntry("hello world".getBytes());
    lh.close();
    LedgerHandle readLh =
        bkc.get()
            .openLedger(lh.getId(), BookKeeper.DigestType.CRC32, dlConf.getBKDigestPW().getBytes());
    Enumeration<LedgerEntry> entries = readLh.readEntries(eid, eid);
    int i = 0;
    while (entries.hasMoreElements()) {
      LedgerEntry entry = entries.nextElement();
      assertEquals("hello world", new String(entry.getEntry(), UTF_8));
      ++i;
    }
    assertEquals(1, i);
  }
  /*
   * (non-Javadoc)
   *
   * @see org.apache.bookkeeper.mledger.ManagedLedger#close()
   */
  @Override
  public synchronized void close() throws InterruptedException, ManagedLedgerException {
    checkFenced();

    for (LedgerHandle ledger : ledgerCache.asMap().values()) {
      log.debug("Closing ledger: {}", ledger.getId());
      try {
        ledger.close();
      } catch (BKException e) {
        throw new ManagedLedgerException(e);
      }
    }

    ledgerCache.invalidateAll();
    log.info("Invalidated {} ledgers in cache", ledgerCache.size());
    factory.close(this);
  }
  /*
   * (non-Javadoc)
   *
   * @see org.apache.bookkeeper.mledger.ManagedLedger#openCursor(java.
   * lang.String)
   */
  @Override
  public synchronized ManagedCursor openCursor(String cursorName)
      throws InterruptedException, ManagedLedgerException {
    checkFenced();

    ManagedCursor cursor = cursors.get(cursorName);

    if (cursor == null) {
      // Create a new one and persist it
      Position position = new Position(currentLedger.getId(), currentLedger.getLastAddConfirmed());

      cursor = new ManagedCursorImpl(this, cursorName, position);
      store.updateConsumer(name, cursorName, position);
      cursors.add(cursor);
    }

    log.debug("[{}] Opened new cursor: {}", this.name, cursor);
    return cursor;
  }