sijie commented on a change in pull request #266: Issue 265: Add persistable bookie status URL: https://github.com/apache/bookkeeper/pull/266#discussion_r128891404
########## File path: bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieInitializationTest.java ########## @@ -632,4 +648,174 @@ private ZooKeeperClient createNewZKClient() throws Exception { .connectString(zkUtil.getZooKeeperConnectString()) .build(); } + + /** + * Check bookie status should be able to persist on disk and retrieve when restart the bookie. + */ + @Test(timeout = 10000) + public void testPersistBookieStatus() throws Exception { + // enable persistent bookie status + File tmpDir = createTempDir("bookie", "test"); + final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() + .setZkServers(zkUtil.getZooKeeperConnectString()) + .setJournalDirName(tmpDir.getPath()) + .setLedgerDirNames(new String[] { tmpDir.getPath() }) + .setReadOnlyModeEnabled(true) + .setPersistBookieStatusEnabled(true); + BookieServer bookieServer = new BookieServer(conf); + bookieServer.start(); + Bookie bookie = bookieServer.getBookie(); + assertFalse(bookie.isReadOnly()); + // transition to readonly mode, bookie status should be persisted in ledger disks + bookie.doTransitionToReadOnlyMode(); + assertTrue(bookie.isReadOnly()); + + // restart bookie should start in read only mode + bookieServer.shutdown(); + bookieServer = new BookieServer(conf); + bookieServer.start(); + bookie = bookieServer.getBookie(); + assertTrue(bookie.isReadOnly()); + // transition to writable mode + bookie.doTransitionToWritableMode(); + // restart bookie should start in writable mode + bookieServer.shutdown(); + bookieServer = new BookieServer(conf); + bookieServer.start(); + bookie = bookieServer.getBookie(); + assertFalse(bookie.isReadOnly()); + bookieServer.shutdown(); + } + + /** + * Check when we start a ReadOnlyBookie, we should ignore bookie status + */ + @Test(timeout = 10000) + public void testReadOnlyBookieShouldIgnoreBookieStatus() throws Exception { + File tmpDir = createTempDir("bookie", "test"); + final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() + .setZkServers(zkUtil.getZooKeeperConnectString()) + .setJournalDirName(tmpDir.getPath()) + .setLedgerDirNames(new String[] { tmpDir.getPath() }) + .setReadOnlyModeEnabled(true) + .setPersistBookieStatusEnabled(true); + // start new bookie + BookieServer bookieServer = new BookieServer(conf); + bookieServer.start(); + Bookie bookie = bookieServer.getBookie(); + // persist bookie status + bookie.doTransitionToReadOnlyMode(); + bookie.doTransitionToWritableMode(); + assertFalse(bookie.isReadOnly()); + bookieServer.shutdown(); + // start read only bookie + final ServerConfiguration readOnlyConf = TestBKConfiguration.newServerConfiguration(); + readOnlyConf.loadConf(conf); + readOnlyConf.setForceReadOnlyBookie(true); + bookieServer = new BookieServer(readOnlyConf); + bookieServer.start(); + bookie = bookieServer.getBookie(); + assertTrue(bookie.isReadOnly()); + // transition to writable should fail + bookie.doTransitionToWritableMode(); + assertTrue(bookie.isReadOnly()); + bookieServer.shutdown(); + } + + /** + * Check that if there's multiple bookie status copies, as long as not all of them are corrupted, + * the bookie status should be retrievable. + */ + @Test(timeout = 10000) + public void testRetrieveBookieStatusWhenStatusFileIsCorrupted() throws Exception { + File[] tmpLedgerDirs = new File[3]; + String[] filePath = new String[tmpLedgerDirs.length]; + for (int i = 0; i < tmpLedgerDirs.length; i++) { + tmpLedgerDirs[i] = createTempDir("bookie", "test" + i); + filePath[i] = tmpLedgerDirs[i].getPath(); + } + final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() + .setZkServers(zkUtil.getZooKeeperConnectString()) + .setJournalDirName(filePath[0]) + .setLedgerDirNames(filePath) + .setReadOnlyModeEnabled(true) + .setPersistBookieStatusEnabled(true); + // start a new bookie + BookieServer bookieServer = new BookieServer(conf); + bookieServer.start(); + // transition in to read only and persist the status on disk + Bookie bookie = bookieServer.getBookie(); + assertFalse(bookie.isReadOnly()); + bookie.doTransitionToReadOnlyMode(); + assertTrue(bookie.isReadOnly()); + // corrupt status file + List<File> ledgerDirs = bookie.getLedgerDirsManager().getAllLedgerDirs(); + corrupteFile(new File(ledgerDirs.get(0), BOOKIE_STATUS_FILENAME)); + corrupteFile(new File(ledgerDirs.get(1), BOOKIE_STATUS_FILENAME)); + // restart the bookie should be in read only mode + bookieServer.shutdown(); + bookieServer = new BookieServer(conf); + bookieServer.start(); + bookie = bookieServer.getBookie(); + assertTrue(bookie.isReadOnly()); + bookieServer.shutdown(); + } + + /** + * Check if the bookie would read the latest status if the status files are not consistent. + * @throws Exception + */ + @Test(timeout = 10000) + public void testReadLatestBookieStatus() throws Exception { + File[] tmpLedgerDirs = new File[3]; + String[] filePath = new String[tmpLedgerDirs.length]; + for (int i = 0; i < tmpLedgerDirs.length; i++) { + tmpLedgerDirs[i] = createTempDir("bookie", "test" + i); + filePath[i] = tmpLedgerDirs[i].getPath(); + } + final ServerConfiguration conf = TestBKConfiguration.newServerConfiguration() + .setZkServers(zkUtil.getZooKeeperConnectString()) + .setJournalDirName(filePath[0]) + .setLedgerDirNames(filePath) + .setReadOnlyModeEnabled(true) + .setPersistBookieStatusEnabled(true); + // start a new bookie + BookieServer bookieServer = new BookieServer(conf); + bookieServer.start(); + // transition in to read only and persist the status on disk + Bookie bookie = bookieServer.getBookie(); + assertFalse(bookie.isReadOnly()); + bookie.doTransitionToReadOnlyMode(); + assertTrue(bookie.isReadOnly()); + // Manually update a status file, so it becomes the latest + Thread.sleep(1); + BookieStatus status = new BookieStatus(); + List<File> dirs = new ArrayList<File>(); + dirs.add(bookie.getLedgerDirsManager().getAllLedgerDirs().get(0)); + status.writeToDirectories(dirs); + // restart the bookie should start in writable state + bookieServer.shutdown(); + bookieServer = new BookieServer(conf); + bookieServer.start(); + bookie = bookieServer.getBookie(); + assertFalse(bookie.isReadOnly()); + bookieServer.shutdown(); + } + + private void corrupteFile(File file) throws IOException { + FileOutputStream fos = new FileOutputStream(file); + BufferedWriter bw = null; + try { + bw = new BufferedWriter(new OutputStreamWriter(fos, UTF_8)); + byte[] bytes = new byte[64]; + new Random().nextBytes(bytes); + bw.write(new String(bytes)); + } finally { + if (bw != null) { + bw.close(); + } + fos.close(); Review comment: bw can be null ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services