void readJournal() throws IOException, BookieException { long startTs = MathUtils.now(); journal.replay( new JournalScanner() { @Override public void process(int journalVersion, long offset, ByteBuffer recBuff) throws IOException { long ledgerId = recBuff.getLong(); long entryId = recBuff.getLong(); try { LOG.debug("Replay journal - ledger id : {}, entry id : {}.", ledgerId, entryId); if (entryId == METAENTRY_ID_LEDGER_KEY) { if (journalVersion >= JournalChannel.V3) { int masterKeyLen = recBuff.getInt(); byte[] masterKey = new byte[masterKeyLen]; recBuff.get(masterKey); masterKeyCache.put(ledgerId, masterKey); } else { throw new IOException( "Invalid journal. Contains journalKey " + " but layout version (" + journalVersion + ") is too old to hold this"); } } else if (entryId == METAENTRY_ID_FENCE_KEY) { if (journalVersion >= JournalChannel.V4) { byte[] key = masterKeyCache.get(ledgerId); if (key == null) { key = ledgerStorage.readMasterKey(ledgerId); } LedgerDescriptor handle = handles.getHandle(ledgerId, key); handle.setFenced(); } else { throw new IOException( "Invalid journal. Contains fenceKey " + " but layout version (" + journalVersion + ") is too old to hold this"); } } else { byte[] key = masterKeyCache.get(ledgerId); if (key == null) { key = ledgerStorage.readMasterKey(ledgerId); } LedgerDescriptor handle = handles.getHandle(ledgerId, key); recBuff.rewind(); handle.addEntry(recBuff); } } catch (NoLedgerException nsle) { LOG.debug("Skip replaying entries of ledger {} since it was deleted.", ledgerId); } catch (BookieException be) { throw new IOException(be); } } }); long elapsedTs = MathUtils.now() - startTs; LOG.info("Finished replaying journal in {} ms.", elapsedTs); }
/** * Fences a ledger. From this point on, clients will be unable to write to this ledger. Only * recoveryAddEntry will be able to add entries to the ledger. This method is idempotent. Once a * ledger is fenced, it can never be unfenced. Fencing a fenced ledger has no effect. */ public SettableFuture<Boolean> fenceLedger(long ledgerId, byte[] masterKey) throws IOException, BookieException { LedgerDescriptor handle = handles.getHandle(ledgerId, masterKey); boolean success; synchronized (handle) { success = handle.setFenced(); } if (success) { // fenced first time, we should add the key to journal ensure we can rebuild ByteBuffer bb = ByteBuffer.allocate(8 + 8); bb.putLong(ledgerId); bb.putLong(METAENTRY_ID_FENCE_KEY); bb.flip(); FutureWriteCallback fwc = new FutureWriteCallback(); LOG.debug("record fenced state for ledger {} in journal.", ledgerId); journal.logAddEntry(bb, fwc, null); return fwc.getResult(); } else { // already fenced SettableFuture<Boolean> successFuture = SettableFuture.create(); successFuture.set(true); return successFuture; } }
/** Add an entry to a ledger as specified by handle. */ private void addEntryInternal( LedgerDescriptor handle, ByteBuffer entry, WriteCallback cb, Object ctx) throws IOException, BookieException { long ledgerId = handle.getLedgerId(); entry.rewind(); long entryId = handle.addEntry(entry); entry.rewind(); LOG.trace("Adding {}@{}", entryId, ledgerId); journal.logAddEntry(entry, cb, ctx); }
@Override public void run() { // bookie thread wait for journal thread try { // start journal journal.start(); // wait until journal quits journal.join(); LOG.info("Journal thread quits."); } catch (InterruptedException ie) { LOG.warn("Interrupted on running journal thread : ", ie); } // if the journal thread quits due to shutting down, it is ok if (!shuttingdown) { // some error found in journal thread and it quits // following add operations to it would hang unit client timeout // so we should let bookie server exists LOG.error("Journal manager quits unexpectedly."); triggerBookieShutdown(ExitCode.BOOKIE_EXCEPTION); } }
// internal shutdown method to let shutdown bookie gracefully // when encountering exception synchronized int shutdown(int exitCode) { try { if (running) { // avoid shutdown twice // the exitCode only set when first shutdown usually due to exception found this.exitCode = exitCode; // mark bookie as in shutting down progress shuttingdown = true; // Shutdown Sync thread syncThread.shutdown(); // Shutdown disk checker ledgerDirsManager.shutdown(); if (indexDirsManager != ledgerDirsManager) { indexDirsManager.shutdown(); } // Shutdown journal journal.shutdown(); this.join(); // Shutdown the EntryLogger which has the GarbageCollector Thread running ledgerStorage.shutdown(); // close Ledger Manager try { activeLedgerManager.close(); activeLedgerManagerFactory.uninitialize(); } catch (IOException ie) { LOG.error("Failed to close active ledger manager : ", ie); } // Shutdown the ZK client if (zk != null) zk.close(); // Shutdown State Service stateService.shutdown(); // setting running to false here, so watch thread in bookie server know it only after bookie // shut down running = false; } } catch (InterruptedException ie) { LOG.error("Interrupted during shutting down bookie : ", ie); } return this.exitCode; }
/** * Retrieve the ledger descriptor for the ledger which entry should be added to. The * LedgerDescriptor returned from this method should be eventually freed with #putHandle(). * * @throws BookieException if masterKey does not match the master key of the ledger */ private LedgerDescriptor getLedgerForEntry(ByteBuffer entry, byte[] masterKey) throws IOException, BookieException { long ledgerId = entry.getLong(); LedgerDescriptor l = handles.getHandle(ledgerId, masterKey); if (!masterKeyCache.containsKey(ledgerId)) { // new handle, we should add the key to journal ensure we can rebuild ByteBuffer bb = ByteBuffer.allocate(8 + 8 + 4 + masterKey.length); bb.putLong(ledgerId); bb.putLong(METAENTRY_ID_LEDGER_KEY); bb.putInt(masterKey.length); bb.put(masterKey); bb.flip(); if (null == masterKeyCache.putIfAbsent(ledgerId, masterKey)) { journal.logAddEntry(bb, new NopWriteCallback(), null); } } return l; }