/** @return a new block container id */ @Override public long getNewContainerId() { synchronized (mBlockContainerIdGenerator) { long containerId = mBlockContainerIdGenerator.getNewContainerId(); writeJournalEntry(mBlockContainerIdGenerator.toJournalEntry()); flushJournal(); return containerId; } }
/** @return a new block container id */ @Override public long getNewContainerId() { synchronized (mBlockContainerIdGenerator) { long containerId = mBlockContainerIdGenerator.getNewContainerId(); if (containerId < mJournaledNextContainerId) { // This container id is within the reserved container ids, so it is safe to return the id // without having to write anything to the journal. return containerId; } // This container id is not safe with respect to the last journaled container id. // Therefore, journal the new state of the container id. This implies that when a master // crashes, the container ids within the reservation which have not been used yet will // never be used. This is a tradeoff between fully utilizing the container id space, vs. // improving master scalability. // TODO(gpang): investigate if dynamic reservation sizes could be effective // Set the next id to journal with a reservation of container ids, to avoid having to write // to the journal for ids within the reservation. mJournaledNextContainerId = containerId + CONTAINER_ID_RESERVATION_SIZE; long counter = appendJournalEntry(getContainerIdJournalEntry()); // This must be flushed while holding the lock on mBlockContainerIdGenerator, in order to // prevent subsequent calls to return container ids that have not been journaled and flushed. waitForJournalFlush(counter); return containerId; } }
@Override public void streamToJournalCheckpoint(JournalOutputStream outputStream) throws IOException { outputStream.writeEntry(mBlockContainerIdGenerator.toJournalEntry()); for (MasterBlockInfo blockInfo : mBlocks.values()) { BlockInfoEntry blockInfoEntry = BlockInfoEntry.newBuilder() .setBlockId(blockInfo.getBlockId()) .setLength(blockInfo.getLength()) .build(); outputStream.writeEntry(JournalEntry.newBuilder().setBlockInfo(blockInfoEntry).build()); } }
@Override public void processJournalEntry(JournalEntry entry) throws IOException { Message innerEntry = JournalProtoUtils.unwrap(entry); // TODO(gene): A better way to process entries besides a huge switch? if (innerEntry instanceof BlockContainerIdGeneratorEntry) { mBlockContainerIdGenerator.setNextContainerId( ((BlockContainerIdGeneratorEntry) innerEntry).getNextContainerId()); } else if (innerEntry instanceof BlockInfoEntry) { BlockInfoEntry blockInfoEntry = (BlockInfoEntry) innerEntry; mBlocks.put( blockInfoEntry.getBlockId(), new MasterBlockInfo(blockInfoEntry.getBlockId(), blockInfoEntry.getLength())); } else { throw new IOException(ExceptionMessage.UNEXPECTED_JOURNAL_ENTRY.getMessage(entry)); } }