You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by iv...@apache.org on 2011/11/04 11:46:45 UTC

svn commit: r1197495 - in /zookeeper/bookkeeper/trunk: ./ bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/ bookkeeper-server/src/test/java/org/apache/bookkeeper/test/

Author: ivank
Date: Fri Nov  4 10:46:44 2011
New Revision: 1197495

URL: http://svn.apache.org/viewvc?rev=1197495&view=rev
Log:
BOOKKEEPER-50: NullPointException at LedgerDescriptor#cmpMasterKey (Sijie Guo via ivank)

Modified:
    zookeeper/bookkeeper/trunk/CHANGES.txt
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/FileInfo.java
    zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BaseTestCase.java

Modified: zookeeper/bookkeeper/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/CHANGES.txt?rev=1197495&r1=1197494&r2=1197495&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/CHANGES.txt (original)
+++ zookeeper/bookkeeper/trunk/CHANGES.txt Fri Nov  4 10:46:44 2011
@@ -60,6 +60,8 @@ BUGFIXES:
 
   BOOKKEEPER-103: ledgerId and entryId is parsed wrong when addEntry (Sijie Guo via ivank)
 
+  BOOKKEEPER-50: NullPointException at LedgerDescriptor#cmpMasterKey (Sijie Guo via ivank)
+
  hedwig-server/
 
   BOOKKEEPER-43: NullPointException when releasing topic (Sijie Guo via breed)

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java?rev=1197495&r1=1197494&r2=1197495&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java Fri Nov  4 10:46:44 2011
@@ -193,7 +193,6 @@ public class Bookie extends Thread {
                     }
                     recBuff.flip();
                     long ledgerId = recBuff.getLong();
-                    // XXX we net to make sure we set the master keys appropriately!
                     LedgerDescriptor handle = getHandle(ledgerId, false);
                     try {
                         recBuff.rewind();
@@ -317,12 +316,29 @@ public class Bookie extends Thread {
         synchronized (ledgers) {
             handle = ledgers.get(ledgerId);
             if (handle == null) {
-                if (readonly) {
-                    throw new NoLedgerException(ledgerId);
+                FileInfo fi = null;
+                try {
+                    // get file info will throw NoLedgerException
+                    fi = ledgerCache.getFileInfo(ledgerId, !readonly);
+
+                    // if an existed ledger index file, we can get its master key
+                    // if an new created ledger index file, we will get a null master key
+                    byte[] existingMasterKey = fi.readMasterKey();
+                    ByteBuffer masterKeyToSet = ByteBuffer.wrap(masterKey);
+                    if (existingMasterKey == null) {
+                        // no master key set before
+                        fi.writeMasterKey(masterKey);
+                    } else if (!masterKeyToSet.equals(ByteBuffer.wrap(existingMasterKey))) {
+                        throw new IOException("Wrong master key for ledger " + ledgerId);
+                    }
+                    handle = createHandle(ledgerId, readonly);
+                    ledgers.put(ledgerId, handle);
+                    handle.setMasterKey(masterKeyToSet);
+                } finally {
+                    if (fi != null) {
+                        fi.release();
+                    }
                 }
-                handle = createHandle(ledgerId, readonly);
-                ledgers.put(ledgerId, handle);
-                handle.setMasterKey(ByteBuffer.wrap(masterKey));
             }
             handle.incRef();
         }
@@ -334,11 +350,26 @@ public class Bookie extends Thread {
         synchronized (ledgers) {
             handle = ledgers.get(ledgerId);
             if (handle == null) {
-                if (readonly) {
-                    throw new NoLedgerException(ledgerId);
+                FileInfo fi = null;
+                try {
+                    // get file info will throw NoLedgerException
+                    fi = ledgerCache.getFileInfo(ledgerId, !readonly);
+
+                    // if an existed ledger index file, we can get its master key
+                    // if an new created ledger index file, we will get a null master key
+                    byte[] existingMasterKey = fi.readMasterKey();
+                    if (existingMasterKey == null) {
+                        throw new IOException("Weird! No master key found in ledger " + ledgerId);
+                    }
+
+                    handle = createHandle(ledgerId, readonly);
+                    ledgers.put(ledgerId, handle);
+                    handle.setMasterKey(ByteBuffer.wrap(existingMasterKey));
+                } finally {
+                    if (fi != null) {
+                        fi.release();
+                    }
                 }
-                handle = createHandle(ledgerId, readonly);
-                ledgers.put(ledgerId, handle);
             }
             handle.incRef();
         }

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/FileInfo.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/FileInfo.java?rev=1197495&r1=1197494&r2=1197495&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/FileInfo.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/FileInfo.java Fri Nov  4 10:46:44 2011
@@ -32,10 +32,25 @@ import org.apache.log4j.Logger;
 /**
  * This is the file handle for a ledger's index file that maps entry ids to location.
  * It is used by LedgerCache.
+ *
+ * <p>
+ * Ledger index file is made of a header and several fixed-length index pages, which records the offsets of data stored in entry loggers
+ * <pre>&lt;header&gt;&lt;index pages&gt;</pre>
+ * <b>Header</b> is formated as below:
+ * <pre>&lt;magic bytes&gt;&lt;len of master key&gt;&lt;master key&gt;</pre>
+ * <ul>
+ * <li>magic bytes: 8 bytes, 'BKLE\0\0\0\0'
+ * <li>len of master key: indicates length of master key. -1 means no master key stored in header.
+ * <li>master key: master key
+ * </ul>
+ * <b>Index page</b> is a fixed-length page, which contains serveral entries which point to the offsets of data stored in entry loggers.
+ * </p>
  */
 class FileInfo {
     static Logger LOG = Logger.getLogger(FileInfo.class);
 
+    static final int NO_MASTER_KEY = -1;
+
     private FileChannel fc;
     private final File lf;
     /**
@@ -52,7 +67,61 @@ class FileInfo {
         size = fc.size();
         if (size == 0) {
             fc.write(ByteBuffer.wrap(header));
+            // write NO_MASTER_KEY, which means there is no master key
+            ByteBuffer buf = ByteBuffer.allocate(4);
+            buf.putInt(NO_MASTER_KEY);
+            buf.flip();
+            fc.write(buf);
+        }
+    }
+
+    /**
+     * Write master key to index file header
+     *
+     * @param masterKey master key to store
+     * @return void
+     * @throws IOException
+     */
+    synchronized public void writeMasterKey(byte[] masterKey) throws IOException {
+        // write master key
+        if (masterKey == null ||
+            masterKey.length + 4 + header.length > START_OF_DATA) {
+            throw new IOException("master key is more than " + (START_OF_DATA - 4 - header.length));
+        }
+
+        int len = masterKey.length;
+        ByteBuffer lenBuf = ByteBuffer.allocate(4);
+        lenBuf.putInt(len);
+        lenBuf.flip();
+        fc.position(header.length);
+        fc.write(lenBuf);
+        fc.write(ByteBuffer.wrap(masterKey));
+    }
+
+    /**
+     * Read master key
+     *
+     * @return master key. null means no master key stored in index header
+     * @throws IOException
+     */
+    synchronized public byte[] readMasterKey() throws IOException {
+        ByteBuffer lenBuf = ByteBuffer.allocate(4);
+        int total = readAbsolute(lenBuf, header.length);
+        if (total != 4) {
+            throw new IOException("Short read during reading master key length");
+        }
+        lenBuf.rewind();
+        int len = lenBuf.getInt();
+        if (len == NO_MASTER_KEY) {
+            return null;
+        }
+
+        byte[] masterKey = new byte[len];
+        total = readAbsolute(ByteBuffer.wrap(masterKey), header.length + 4);
+        if (total != len) {
+            throw new IOException("Short read during reading master key");
         }
+        return masterKey;
     }
 
     synchronized public long size() {
@@ -64,13 +133,19 @@ class FileInfo {
     }
 
     synchronized public int read(ByteBuffer bb, long position) throws IOException {
+        return readAbsolute(bb, position + START_OF_DATA);
+    }
+
+    private int readAbsolute(ByteBuffer bb, long start) throws IOException {
         int total = 0;
         while(bb.remaining() > 0) {
-            int rc = fc.read(bb, position+START_OF_DATA);
+            int rc = fc.read(bb, start);
             if (rc <= 0) {
                 throw new IOException("Short read");
             }
             total += rc;
+            // should move read position
+            start += rc;
         }
         return total;
     }

Modified: zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BaseTestCase.java
URL: http://svn.apache.org/viewvc/zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BaseTestCase.java?rev=1197495&r1=1197494&r2=1197495&view=diff
==============================================================================
--- zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BaseTestCase.java (original)
+++ zookeeper/bookkeeper/trunk/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BaseTestCase.java Fri Nov  4 10:46:44 2011
@@ -21,6 +21,7 @@
 
 package org.apache.bookkeeper.test;
 
+import java.io.IOException;
 import java.io.File;
 import java.net.InetSocketAddress;
 import java.util.ArrayList;
@@ -124,6 +125,29 @@ public abstract class BaseTestCase exten
         }
     }
 
+    /**
+     * Restart bookie servers
+     *
+     * @throws InterruptedException
+     * @throws IOException
+     */
+    protected void restartBookies() throws InterruptedException, IOException {
+        // shut down bookie server
+        for (BookieServer server : bs) {
+            server.shutdown();
+        }
+        bs.clear();
+        Thread.sleep(1000);
+        // restart them to ensure we can't 
+        int j = 0;
+        for (File f : tmpDirs) {
+            BookieServer server = new BookieServer(initialPort + j, HOSTPORT, f, new File[] { f });
+            server.start();
+            bs.add(server);
+            j++;
+        }
+    }
+
     @After
     @Override
     public void tearDown() throws Exception {