You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bookkeeper.apache.org by si...@apache.org on 2018/01/23 05:33:06 UTC

[bookkeeper] branch master updated: ISSUE #1026: initbookie cmd

This is an automated email from the ASF dual-hosted git repository.

sijie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git


The following commit(s) were added to refs/heads/master by this push:
     new 1d7a489  ISSUE #1026: initbookie cmd
1d7a489 is described below

commit 1d7a489afb8fee8754b2da1d45745a47542eeca7
Author: cguttapalem <cg...@salesforce.com>
AuthorDate: Mon Jan 22 21:32:58 2018 -0800

    ISSUE #1026: initbookie cmd
    
    Descriptions of the changes in this PR:
    
    - adding a new BookieShell command - "initbookie" command to decouple from
    bookieformat. This command initializes bookie, by making sure that the
    journalDirs, ledgerDirs and indexDirs are empty and there is no
    registered Bookie with this BookieId.
    
    Master Issue: #1027
    
    Author: cguttapalem <cg...@salesforce.com>
    
    Reviewers: Sijie Guo <si...@apache.org>
    
    This closes #1027 from reddycharan/initbookiecmd, closes #1026
---
 .../org/apache/bookkeeper/bookie/BookieShell.java  | 36 +++++++++++
 .../apache/bookkeeper/client/BookKeeperAdmin.java  | 69 ++++++++++++++++++++++
 .../bookkeeper/discover/RegistrationManager.java   | 11 ++++
 .../bookkeeper/discover/ZKRegistrationManager.java | 16 +++++
 .../bookkeeper/client/BookKeeperAdminTest.java     | 45 ++++++++++++++
 5 files changed, 177 insertions(+)

diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieShell.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieShell.java
index 5235110..82ad868 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieShell.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieShell.java
@@ -139,6 +139,7 @@ public class BookieShell implements Tool {
     static final String LEDGERID_FORMATTER_OPT = "ledgeridformat";
 
     static final String CMD_METAFORMAT = "metaformat";
+    static final String CMD_INITBOOKIE = "initbookie";
     static final String CMD_BOOKIEFORMAT = "bookieformat";
     static final String CMD_RECOVER = "recover";
     static final String CMD_LEDGER = "ledger";
@@ -328,6 +329,40 @@ public class BookieShell implements Tool {
     }
 
     /**
+     * Initializes bookie, by making sure that the journalDir, ledgerDirs and
+     * indexDirs are empty and there is no registered Bookie with this BookieId.
+     */
+    class InitBookieCmd extends MyCommand {
+        Options opts = new Options();
+
+        public InitBookieCmd() {
+            super(CMD_INITBOOKIE);
+        }
+
+        @Override
+        Options getOptions() {
+            return opts;
+        }
+
+        @Override
+        String getDescription() {
+            return "Initialize new Bookie";
+        }
+
+        @Override
+        String getUsage() {
+            return CMD_INITBOOKIE;
+        }
+
+        @Override
+        int runCmd(CommandLine cmdLine) throws Exception {
+            ServerConfiguration conf = new ServerConfiguration(bkConf);
+            boolean result = BookKeeperAdmin.initBookie(conf);
+            return (result) ? 0 : 1;
+        }
+    }
+
+    /**
      * Recover command for ledger data recovery for failed bookie.
      */
     class RecoverCmd extends MyCommand {
@@ -2526,6 +2561,7 @@ public class BookieShell implements Tool {
 
     {
         commands.put(CMD_METAFORMAT, new MetaFormatCmd());
+        commands.put(CMD_INITBOOKIE, new InitBookieCmd());
         commands.put(CMD_BOOKIEFORMAT, new BookieFormatCmd());
         commands.put(CMD_RECOVER, new RecoverCmd());
         commands.put(CMD_LEDGER, new LedgerCmd());
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperAdmin.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperAdmin.java
index 2c5b9df..85527d6 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperAdmin.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperAdmin.java
@@ -26,6 +26,8 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.AbstractFuture;
+
+import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -48,6 +50,9 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Predicate;
+
+import org.apache.bookkeeper.bookie.Bookie;
+import org.apache.bookkeeper.bookie.BookieException;
 import org.apache.bookkeeper.client.AsyncCallback.OpenCallback;
 import org.apache.bookkeeper.client.AsyncCallback.RecoverCallback;
 import org.apache.bookkeeper.client.LedgerFragmentReplicator.SingleFragmentCallback;
@@ -1155,6 +1160,70 @@ public class BookKeeperAdmin implements AutoCloseable {
     }
 
     /**
+     * Initializes bookie, by making sure that the journalDir, ledgerDirs and
+     * indexDirs are empty and there is no registered Bookie with this BookieId.
+     *
+     * @param conf
+     * @return
+     * @throws Exception
+     */
+    public static boolean initBookie(ServerConfiguration conf) throws Exception {
+        /*
+         * make sure that journalDirs, ledgerDirs and indexDirs are empty
+         */
+        File[] journalDirs = conf.getJournalDirs();
+        if (!validateDirectoriesAreEmpty(journalDirs, "JournalDir")) {
+            return false;
+        }
+
+        File[] ledgerDirs = conf.getLedgerDirs();
+        if (!validateDirectoriesAreEmpty(ledgerDirs, "LedgerDir")) {
+            return false;
+        }
+
+        File[] indexDirs = conf.getIndexDirs();
+        if (indexDirs != null) {
+            if (!validateDirectoriesAreEmpty(indexDirs, "IndexDir")) {
+                return false;
+            }
+        }
+
+        try (RegistrationManager rm = RegistrationManager.instantiateRegistrationManager(conf)) {
+            /*
+             * make sure that there is no bookie registered with the same
+             * bookieid and the cookie for the same bookieid is not existing.
+             */
+            String bookieId = Bookie.getBookieAddress(conf).toString();
+            if (rm.isBookieRegistered(bookieId)) {
+                LOG.error("Bookie with bookieId: {} is still registered, "
+                        + "If this node is running bookie process, try stopping it first.", bookieId);
+                return false;
+            }
+
+            try {
+                rm.readCookie(bookieId);
+                LOG.error("Cookie still exists in the ZK for this bookie: {}, try formatting the bookie", bookieId);
+                return false;
+            } catch (BookieException.CookieNotFoundException nfe) {
+                // it is expected for readCookie to fail with
+                // BookieException.CookieNotFoundException
+            }
+            return true;
+        }
+    }
+
+    private static boolean validateDirectoriesAreEmpty(File[] dirs, String typeOfDir) {
+        for (File dir : dirs) {
+            File[] dirFiles = dir.listFiles();
+            if ((dirFiles != null) && dirFiles.length != 0) {
+                LOG.error("{}: {} is existing and its not empty, try formatting the bookie", typeOfDir, dir);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
      * This method returns an iterable object for the list of ledger identifiers of
      * the ledgers currently available.
      *
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/discover/RegistrationManager.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/discover/RegistrationManager.java
index d4a021b..d0c304b 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/discover/RegistrationManager.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/discover/RegistrationManager.java
@@ -99,6 +99,17 @@ public interface RegistrationManager extends AutoCloseable {
     void unregisterBookie(String bookieId, boolean readOnly) throws BookieException;
 
     /**
+     * Checks if Bookie with the given BookieId is registered as readwrite or
+     * readonly bookie.
+     *
+     * @param bookieId bookie id
+     * @return returns true if a bookie with bookieid is currently registered as
+     *          readwrite or readonly bookie.
+     * @throws BookieException
+     */
+    boolean isBookieRegistered(String bookieId) throws BookieException;
+
+    /**
      * Write the cookie data, which will be used for verifying the integrity of the bookie environment.
      *
      * @param bookieId bookie id
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/discover/ZKRegistrationManager.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/discover/ZKRegistrationManager.java
index 37aea09..527af78 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/discover/ZKRegistrationManager.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/discover/ZKRegistrationManager.java
@@ -513,4 +513,20 @@ public class ZKRegistrationManager implements RegistrationManager {
             return true;
         }
     }
+
+    @Override
+    public boolean isBookieRegistered(String bookieId) throws BookieException {
+        String regPath = bookieRegistrationPath + "/" + bookieId;
+        String readonlyRegPath = bookieReadonlyRegistrationPath + "/" + bookieId;
+        try {
+            return ((null != zk.exists(regPath, false)) || (null != zk.exists(readonlyRegPath, false)));
+        } catch (KeeperException e) {
+            log.error("ZK exception while checking registration ephemeral znodes for BookieId: {}", bookieId, e);
+            throw new MetadataStoreException(e);
+        } catch (InterruptedException e) {
+            log.error("InterruptedException while checking registration ephemeral znodes for BookieId: {}", bookieId,
+                    e);
+            throw new MetadataStoreException(e);
+        }
+    }
 }
diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperAdminTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperAdminTest.java
index 14551a8..3f3e840 100644
--- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperAdminTest.java
+++ b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/BookKeeperAdminTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.io.File;
 import java.util.Iterator;
 
 import org.apache.bookkeeper.bookie.Bookie;
@@ -34,6 +35,9 @@ import org.apache.bookkeeper.meta.ZkLedgerUnderreplicationManager;
 import org.apache.bookkeeper.replication.ReplicationException.UnavailableException;
 import org.apache.bookkeeper.test.BookKeeperClusterTestCase;
 import org.apache.bookkeeper.test.annotations.FlakyTest;
+import org.apache.bookkeeper.util.BookKeeperConstants;
+import org.apache.commons.io.FileUtils;
+import org.junit.Assert;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -230,4 +234,45 @@ public class BookKeeperAdminTest extends BookKeeperClusterTestCase {
         }
         bkAdmin.close();
     }
+
+    @Test(timeout = 6000000)
+    public void testBookieInit() throws Exception {
+        int bookieindex = 0;
+        ServerConfiguration confOfExistingBookie = bsConfs.get(bookieindex);
+        Assert.assertFalse("initBookie shouldn't have succeeded, since bookie is still running with that configuration",
+                BookKeeperAdmin.initBookie(confOfExistingBookie));
+        killBookie(bookieindex);
+        Assert.assertFalse("initBookie shouldn't have succeeded, since previous bookie is not formatted yet",
+                BookKeeperAdmin.initBookie(confOfExistingBookie));
+
+        File[] journalDirs = confOfExistingBookie.getJournalDirs();
+        for (File journalDir : journalDirs) {
+            FileUtils.deleteDirectory(journalDir);
+        }
+        Assert.assertFalse("initBookie shouldn't have succeeded, since previous bookie is not formatted yet completely",
+                BookKeeperAdmin.initBookie(confOfExistingBookie));
+
+        File[] ledgerDirs = confOfExistingBookie.getLedgerDirs();
+        for (File ledgerDir : ledgerDirs) {
+            FileUtils.deleteDirectory(ledgerDir);
+        }
+        Assert.assertFalse("initBookie shouldn't have succeeded, since previous bookie is not formatted yet completely",
+                BookKeeperAdmin.initBookie(confOfExistingBookie));
+
+        File[] indexDirs = confOfExistingBookie.getIndexDirs();
+        if (indexDirs != null) {
+            for (File indexDir : indexDirs) {
+                FileUtils.deleteDirectory(indexDir);
+            }
+        }
+        Assert.assertFalse("initBookie shouldn't have succeeded, since cookie in ZK is not deleted yet",
+                BookKeeperAdmin.initBookie(confOfExistingBookie));
+        String bookieId = Bookie.getBookieAddress(confOfExistingBookie).toString();
+        String bookieCookiePath = confOfExistingBookie.getZkLedgersRootPath() + "/" + BookKeeperConstants.COOKIE_NODE
+                + "/" + bookieId;
+        zkc.delete(bookieCookiePath, -1);
+
+        Assert.assertTrue("initBookie shouldn't succeeded",
+                BookKeeperAdmin.initBookie(confOfExistingBookie));
+    }
 }

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.