Repository: diennea/herddb
Pull request #733 (2020-11-16 14:08:54)

Upgrade to BookKeeper 4.12.0 and enable BookieID
- Upgrade to Apache BookKeeper 4.12.0
- Fix code, that now uses BookieId instead of BookieSocketAddress
- Add new configuration parameter **server.bookkeeper.bookieid.enabled**, disabled by default in "embedded" case

With server.bookkeeper.bookieid.enabled the bookie will be configured to use the same nodeid as the server, this way basically the bookie doesn't depend on the "current" network address anymore.

With this patch the id of the bookie and of the data is tied to the 'nodeid', as we already had for the rest of HerdDB


Patch:
diff --git a/herddb-core/src/main/java/herddb/cluster/EmbeddedBookie.java b/herddb-core/src/main/java/herddb/cluster/EmbeddedBookie.java
index d9c1bf5f..90c3301e 100644
--- a/herddb-core/src/main/java/herddb/cluster/EmbeddedBookie.java
+++ b/herddb-core/src/main/java/herddb/cluster/EmbeddedBookie.java
@@ -35,7 +35,6 @@ import java.util.logging.Logger;
 import java.util.stream.Collectors;
 import org.apache.bookkeeper.bookie.Bookie;
 import org.apache.bookkeeper.client.BookKeeperAdmin;
-import org.apache.bookkeeper.discover.BookieServiceInfo;
 import org.apache.bookkeeper.meta.HierarchicalLedgerManagerFactory;
 import org.apache.bookkeeper.proto.BookieServer;
 import org.apache.bookkeeper.stats.NullStatsLogger;
@@ -89,6 +88,17 @@ public class EmbeddedBookie implements AutoCloseable {
             }
             port = _port;
         }
+        boolean enableBookieId = configuration.getBoolean(ServerConfiguration.PROPERTY_BOOKKEEPER_BOOKIE_BOOKIEID_ENABLED, ServerConfiguration.PROPERTY_BOOKKEEPER_BOOKIE_BOOKIEID_ENABLED_DEFAULT);
+        if (enableBookieId) {
+            String bookieId = configuration.getString(ServerConfiguration.PROPERTY_NODEID, "");
+            if (bookieId.isEmpty()) {
+                throw new RuntimeException("Cannot use BookieId as main " + ServerConfiguration.PROPERTY_NODEID + " is not set");
+            }
+            LOG.log(Level.SEVERE, "As configuration parameter "
+                    + ServerConfiguration.PROPERTY_BOOKKEEPER_BOOKIE_BOOKIEID_ENABLED
+                    + " is {0},I have choosen to use the main server node id (" + ServerConfiguration.PROPERTY_NODEID + ") {1}", new Object[] {enableBookieId, bookieId});
+            conf.setBookieId(bookieId);
+        }
         conf.setBookiePort(port);
         Files.createDirectories(bookie_dir);
         Path bookie_data_dir = bookie_dir.resolve("bookie_data").toAbsolutePath();
@@ -144,7 +154,7 @@ public class EmbeddedBookie implements AutoCloseable {
             }
         }
 
-        bookieServer = new BookieServer(conf, statsLogger, BookieServiceInfo.NO_INFO);
+        bookieServer = new BookieServer(conf, statsLogger, null);
         bookieServer.start();
         for (int i = 0; i < 100; i++) {
             if (bookieServer.getBookie().isRunning()) {
@@ -232,4 +242,8 @@ public class EmbeddedBookie implements AutoCloseable {
         message.append(port);
         Files.write(file, message.toString().getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE_NEW);
     }
+
+    public String getBookieId() throws Exception {
+        return bookieServer.getBookieId().toString();
+    }
 }
diff --git a/herddb-core/src/main/java/herddb/cluster/PreferLocalBookiePlacementPolicy.java b/herddb-core/src/main/java/herddb/cluster/PreferLocalBookiePlacementPolicy.java
index d9a9459f..01546dbe 100644
--- a/herddb-core/src/main/java/herddb/cluster/PreferLocalBookiePlacementPolicy.java
+++ b/herddb-core/src/main/java/herddb/cluster/PreferLocalBookiePlacementPolicy.java
@@ -35,8 +35,9 @@ import org.apache.bookkeeper.client.DistributionSchedule;
 import org.apache.bookkeeper.client.EnsemblePlacementPolicy;
 import org.apache.bookkeeper.conf.ClientConfiguration;
 import org.apache.bookkeeper.feature.FeatureProvider;
-import org.apache.bookkeeper.net.BookieSocketAddress;
+import org.apache.bookkeeper.net.BookieId;
 import org.apache.bookkeeper.net.DNSToSwitchMapping;
+import org.apache.bookkeeper.proto.BookieAddressResolver;
 import org.apache.bookkeeper.proto.LocalBookiesRegistry;
 import org.apache.bookkeeper.stats.StatsLogger;
 
@@ -47,14 +48,15 @@ import org.apache.bookkeeper.stats.StatsLogger;
  */
 public class PreferLocalBookiePlacementPolicy implements EnsemblePlacementPolicy {
 
-    private Set<BookieSocketAddress> knownBookies = new HashSet<>();
+    private Set<BookieId> knownBookies = new HashSet<>();
 
     @Override
     public EnsemblePlacementPolicy initialize(
             ClientConfiguration conf,
             Optional<DNSToSwitchMapping> optionalDnsResolver,
             HashedWheelTimer hashedWheelTimer,
-            FeatureProvider featureProvider, StatsLogger statsLogger
+            FeatureProvider featureProvider, StatsLogger statsLogger,
+            BookieAddressResolver bookieAddressResolver
     ) {
         return this;
     }
@@ -65,11 +67,11 @@ public class PreferLocalBookiePlacementPolicy implements EnsemblePlacementPolicy
     }
 
     @Override
-    public synchronized Set<BookieSocketAddress> onClusterChanged(
-            Set<BookieSocketAddress> writableBookies,
-            Set<BookieSocketAddress> readOnlyBookies
+    public synchronized Set<BookieId> onClusterChanged(
+            Set<BookieId> writableBookies,
+            Set<BookieId> readOnlyBookies
     ) {
-        HashSet<BookieSocketAddress> deadBookies;
+        HashSet<BookieId> deadBookies;
         deadBookies = new HashSet<>(knownBookies);
         deadBookies.removeAll(writableBookies);
         // readonly bookies should not be treated as dead bookies
@@ -79,55 +81,55 @@ public class PreferLocalBookiePlacementPolicy implements EnsemblePlacementPolicy
     }
 
     @Override
-    public PlacementResult<BookieSocketAddress> replaceBookie(
+    public PlacementResult<BookieId> replaceBookie(
             int ensembleSize,
             int writeQuorumSize,
             int ackQuorumSize,
             Map<String, byte[]> customMetadata,
-            List<BookieSocketAddress> currentEnsemble,
-            BookieSocketAddress bookieToReplace,
-            Set<BookieSocketAddress> excludeBookies
+            List<BookieId> currentEnsemble,
+            BookieId bookieToReplace,
+            Set<BookieId> excludeBookies
     ) throws BKNotEnoughBookiesException {
         excludeBookies.addAll(currentEnsemble);
-        PlacementResult<List<BookieSocketAddress>> list = newEnsemble(1, 1, 1, customMetadata, excludeBookies);
+        PlacementResult<List<BookieId>> list = newEnsemble(1, 1, 1, customMetadata, excludeBookies);
         return PlacementResult.of(list.getResult().get(0), PlacementPolicyAdherence.MEETS_STRICT);
     }
 
     @Override
-    public DistributionSchedule.WriteSet reorderReadSequence(List<BookieSocketAddress> ensemble, BookiesHealthInfo bookiesHealthInfo, DistributionSchedule.WriteSet writeSet) {
+    public DistributionSchedule.WriteSet reorderReadSequence(List<BookieId> ensemble, BookiesHealthInfo bookiesHealthInfo, DistributionSchedule.WriteSet writeSet) {
         return writeSet;
     }
 
     @Override
-    public DistributionSchedule.WriteSet reorderReadLACSequence(List<BookieSocketAddress> ensemble, BookiesHealthInfo bookiesHealthInfo, DistributionSchedule.WriteSet writeSet) {
+    public DistributionSchedule.WriteSet reorderReadLACSequence(List<BookieId> ensemble, BookiesHealthInfo bookiesHealthInfo, DistributionSchedule.WriteSet writeSet) {
         return writeSet;
     }
 
     @Override
-    public void registerSlowBookie(BookieSocketAddress bookieSocketAddress, long entryId) {
+    public void registerSlowBookie(BookieId bookieSocketAddress, long entryId) {
     }
 
     @Override
-    public PlacementResult<List<BookieSocketAddress>> newEnsemble(
+    public PlacementResult<List<BookieId>> newEnsemble(
             int ensembleSize,
             int writeQuorumSize,
             int ackQuorumSize,
             Map<String, byte[]> customMetadata,
-            Set<BookieSocketAddress> excludeBookies
+            Set<BookieId> excludeBookies
     )
             throws BKNotEnoughBookiesException {
 
-        ArrayList<BookieSocketAddress> newBookies = new ArrayList<>(ensembleSize);
+        ArrayList<BookieId> newBookies = new ArrayList<>(ensembleSize);
         if (ensembleSize <= 0) {
             return PlacementResult.of(newBookies, PlacementPolicyAdherence.MEETS_STRICT);
         }
-        List<BookieSocketAddress> allBookies;
+        List<BookieId> allBookies;
         synchronized (this) {
             allBookies = new ArrayList<>(knownBookies);
         }
 
-        BookieSocketAddress localBookie = null;
-        for (BookieSocketAddress bookie : allBookies) {
+        BookieId localBookie = null;
+        for (BookieId bookie : allBookies) {
             if (excludeBookies.contains(bookie)) {
                 continue;
             }
@@ -149,7 +151,7 @@ public class PreferLocalBookiePlacementPolicy implements EnsemblePlacementPolicy
         }
 
         Collections.shuffle(allBookies);
-        for (BookieSocketAddress bookie : allBookies) {
+        for (BookieId bookie : allBookies) {
             if (excludeBookies.contains(bookie)) {
                 continue;
             }
@@ -164,7 +166,7 @@ public class PreferLocalBookiePlacementPolicy implements EnsemblePlacementPolicy
     }
 
     @Override
-    public PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy(List<BookieSocketAddress> ensembleList,
+    public PlacementPolicyAdherence isEnsembleAdheringToPlacementPolicy(List<BookieId> ensembleList,
             int writeQuorumSize, int ackQuorumSize) {
         return PlacementPolicyAdherence.MEETS_STRICT;
     }
diff --git a/herddb-core/src/main/java/herddb/server/Server.java b/herddb-core/src/main/java/herddb/server/Server.java
index b7fcf93d..7930a3ea 100644
--- a/herddb-core/src/main/java/herddb/server/Server.java
+++ b/herddb-core/src/main/java/herddb/server/Server.java
@@ -207,6 +207,8 @@ public class Server implements AutoCloseable, ServerSideConnectionAcceptor<Serve
                         LOGGER.info("Generated new node id " + nodeId);
                     }
                     localNodeIdManager.persistLocalNodeId(nodeId);
+                    // let downstream code see this new id (Embedded Bookie for instance)
+                    configuration.set(ServerConfiguration.PROPERTY_NODEID, nodeId);
                 }
             } catch (IOException | MetadataStorageManagerException error) {
                 LOGGER.log(Level.SEVERE, "Fatal error while generating the local node ID", error);
@@ -488,4 +490,8 @@ public class Server implements AutoCloseable, ServerSideConnectionAcceptor<Serve
                 .collect(Collectors.toList()));
     }
 
+    public EmbeddedBookie getEmbeddedBookie() {
+        return embeddedBookie;
+    }
+
 }
diff --git a/herddb-core/src/main/java/herddb/server/ServerConfiguration.java b/herddb-core/src/main/java/herddb/server/ServerConfiguration.java
index 66f37df5..27920870 100644
--- a/herddb-core/src/main/java/herddb/server/ServerConfiguration.java
+++ b/herddb-core/src/main/java/herddb/server/ServerConfiguration.java
@@ -136,6 +136,9 @@ public final class ServerConfiguration {
     public static final String PROPERTY_BOOKKEEPER_BOOKIE_PORT = "server.bookkeeper.port";
     public static final int PROPERTY_BOOKKEEPER_BOOKIE_PORT_DEFAULT = 3181;
 
+    public static final String PROPERTY_BOOKKEEPER_BOOKIE_BOOKIEID_ENABLED = "server.bookkeeper.bookieid.enabled";
+    public static final boolean PROPERTY_BOOKKEEPER_BOOKIE_BOOKIEID_ENABLED_DEFAULT = false;
+
     public static final String PROPERTY_BOOKKEEPER_LEDGERS_PATH = "server.bookkeeper.ledgers.path";
     public static final String PROPERTY_BOOKKEEPER_LEDGERS_PATH_DEFAULT = "/ledgers";
 
diff --git a/herddb-services/src/main/resources/conf/server.properties b/herddb-services/src/main/resources/conf/server.properties
index a06e0f71..fcf281e1 100644
--- a/herddb-services/src/main/resources/conf/server.properties
+++ b/herddb-services/src/main/resources/conf/server.properties
@@ -121,6 +121,12 @@ server.bookkeeper.max.idle.time=10000
 # if you are using diskless-clustermode it is better to not start the embedded
 # bookie, otherwise it is better to start the standard cluster mode
 server.bookkeeper.start=true
+
+# use the server.node.id value as BookieId
+# if you do not use this option the Bookie will use the network address
+# of this machine and you won't be able to easily change it
+server.bookkeeper.bookieid.enabled=true
+
 # if you leave port to zero a random port will be used an then persisted to bookie_port file
 # bookkeeper uses local hostname and this port to identify bookies
 server.bookkeeper.port=0
diff --git a/pom.xml b/pom.xml
index 8a0fa0d3..cf1599a2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -101,7 +101,7 @@
         <libs.slf4j>1.7.29</libs.slf4j>
         <libs.commonscollections>3.2.2</libs.commonscollections>
         <libs.lz4>1.3.0</libs.lz4>
-        <libs.bookkeeper>4.11.1</libs.bookkeeper>
+        <libs.bookkeeper>4.12.0</libs.bookkeeper>
         <libs.jersey>2.26</libs.jersey>
         <libs.jcipi-annotations>1.0</libs.jcipi-annotations>
         <libs.spotbugsannotations>3.1.8</libs.spotbugsannotations>


Test patch:
diff --git a/herddb-core/src/test/java/herddb/client/SimpleClientServerTest.java b/herddb-core/src/test/java/herddb/client/SimpleClientServerTest.java
index bd4b7806..8455f0b7 100644
--- a/herddb-core/src/test/java/herddb/client/SimpleClientServerTest.java
+++ b/herddb-core/src/test/java/herddb/client/SimpleClientServerTest.java
@@ -170,10 +170,11 @@ public class SimpleClientServerTest {
                             assertEquals(RawString.of("server.base.dir"), name);
                             RawString value = (RawString) aa.get("value");
                             assertEquals(RawString.of(_baseDir), value);
-                        } else {
-                            assertEquals(RawString.of("server.port"), name);
+                        } else if (RawString.of("server.port").equals(name)) {
                             RawString value = (RawString) aa.get("value");
                             assertEquals(RawString.of("0"), value);
+                        } else {
+                            assertEquals(RawString.of("server.node.id"), name);
                         }
                     }
                 }
diff --git a/herddb-core/src/test/java/herddb/cluster/PreferLocalBookiePlacementPolicyTest.java b/herddb-core/src/test/java/herddb/cluster/PreferLocalBookiePlacementPolicyTest.java
index 204a4b30..60877315 100644
--- a/herddb-core/src/test/java/herddb/cluster/PreferLocalBookiePlacementPolicyTest.java
+++ b/herddb-core/src/test/java/herddb/cluster/PreferLocalBookiePlacementPolicyTest.java
@@ -27,6 +27,7 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import org.apache.bookkeeper.net.BookieId;
 import org.apache.bookkeeper.net.BookieSocketAddress;
 import org.junit.Test;
 
@@ -43,8 +44,8 @@ public class PreferLocalBookiePlacementPolicyTest {
     static {
         try {
             Class<?> localBookiesRegistry = Class.forName("org.apache.bookkeeper.proto.LocalBookiesRegistry");
-            registerLocalBookieAddress = localBookiesRegistry.getDeclaredMethod("registerLocalBookieAddress", BookieSocketAddress.class);
-            unregisterLocalBookieAddress = localBookiesRegistry.getDeclaredMethod("unregisterLocalBookieAddress", BookieSocketAddress.class);
+            registerLocalBookieAddress = localBookiesRegistry.getDeclaredMethod("registerLocalBookieAddress", BookieId.class);
+            unregisterLocalBookieAddress = localBookiesRegistry.getDeclaredMethod("unregisterLocalBookieAddress", BookieId.class);
             registerLocalBookieAddress.setAccessible(true);
             unregisterLocalBookieAddress.setAccessible(true);
         } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
@@ -55,22 +56,22 @@ public class PreferLocalBookiePlacementPolicyTest {
     @Test
     public void testEnsamblePolicySingle() throws Exception {
 
-        BookieSocketAddress a = new BookieSocketAddress("a.localhost", 3181);
+        BookieId a = new BookieSocketAddress("a.localhost", 3181).toBookieId();
 
-        Set<BookieSocketAddress> writableBookies = new HashSet<>();
+        Set<BookieId> writableBookies = new HashSet<>();
         writableBookies.add(a);
 
         registerLocalBookieAddress.invoke(null, a);
 
         try {
-            Set<BookieSocketAddress> readOnlyBookies = Collections.emptySet();
+            Set<BookieId> readOnlyBookies = Collections.emptySet();
 
             PreferLocalBookiePlacementPolicy policy = new PreferLocalBookiePlacementPolicy();
-            Set<BookieSocketAddress> deadBookies = policy.onClusterChanged(writableBookies, readOnlyBookies);
+            Set<BookieId> deadBookies = policy.onClusterChanged(writableBookies, readOnlyBookies);
 
             assertTrue(deadBookies.isEmpty());
 
-            List<BookieSocketAddress> ensemble =
+            List<BookieId> ensemble =
                     policy.newEnsemble(1, 1, 1, Collections.emptyMap(), Collections.emptySet()).getResult();
             System.out.println(ensemble);
             assertEquals(1, ensemble.size());
@@ -83,13 +84,13 @@ public class PreferLocalBookiePlacementPolicyTest {
     @Test
     public void testEnsamblePolicyMultiple() throws Exception {
 
-        BookieSocketAddress a = new BookieSocketAddress("a.localhost", 3181);
-        BookieSocketAddress b = new BookieSocketAddress("b.localhost", 3181);
-        BookieSocketAddress c = new BookieSocketAddress("c.localhost", 3181);
-        BookieSocketAddress d = new BookieSocketAddress("d.localhost", 3181);
-        BookieSocketAddress e = new BookieSocketAddress("e.localhost", 3181);
+        BookieId a = new BookieSocketAddress("a.localhost", 3181).toBookieId();
+        BookieId b = new BookieSocketAddress("b.localhost", 3181).toBookieId();
+        BookieId c = new BookieSocketAddress("c.localhost", 3181).toBookieId();
+        BookieId d = new BookieSocketAddress("d.localhost", 3181).toBookieId();
+        BookieId e = new BookieSocketAddress("e.localhost", 3181).toBookieId();
 
-        Set<BookieSocketAddress> writableBookies = new HashSet<>();
+        Set<BookieId> writableBookies = new HashSet<>();
         writableBookies.add(a);
         writableBookies.add(b);
         writableBookies.add(c);
@@ -99,14 +100,14 @@ public class PreferLocalBookiePlacementPolicyTest {
         registerLocalBookieAddress.invoke(null, c);
 
         try {
-            Set<BookieSocketAddress> readOnlyBookies = Collections.emptySet();
+            Set<BookieId> readOnlyBookies = Collections.emptySet();
 
             PreferLocalBookiePlacementPolicy policy = new PreferLocalBookiePlacementPolicy();
-            Set<BookieSocketAddress> deadBookies = policy.onClusterChanged(writableBookies, readOnlyBookies);
+            Set<BookieId> deadBookies = policy.onClusterChanged(writableBookies, readOnlyBookies);
 
             assertTrue(deadBookies.isEmpty());
 
-            List<BookieSocketAddress> ensemble =
+            List<BookieId> ensemble =
                     policy.newEnsemble(3, 2, 2, Collections.emptyMap(), Collections.emptySet()).getResult();
             System.out.println(ensemble);
             assertEquals(3, ensemble.size());
diff --git a/herddb-core/src/test/java/herddb/cluster/bookkeeper/BookKeeperCommitLogTest.java b/herddb-core/src/test/java/herddb/cluster/bookkeeper/BookKeeperCommitLogTest.java
index 80bdf1a4..d39142a3 100644
--- a/herddb-core/src/test/java/herddb/cluster/bookkeeper/BookKeeperCommitLogTest.java
+++ b/herddb-core/src/test/java/herddb/cluster/bookkeeper/BookKeeperCommitLogTest.java
@@ -46,6 +46,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 import org.apache.bookkeeper.common.concurrent.FutureUtils;
+import org.apache.bookkeeper.net.BookieId;
 import org.apache.bookkeeper.stats.NullStatsLogger;
 import org.junit.After;
 import org.junit.Before;
@@ -431,7 +432,7 @@ public class BookKeeperCommitLogTest {
 
     @Test
     public void testFollowEmptyLedgerBookieDown() throws Exception {
-        String secondBookie = testEnv.startNewBookie();
+        BookieId secondBookie = testEnv.startNewBookie();
         final String tableSpaceUUID = UUID.randomUUID().toString();
         final String name = TableSpace.DEFAULT;
         final String nodeid = "nodeid";
diff --git a/herddb-core/src/test/java/herddb/cluster/bookkeeper/BookieNotAvailableTest.java b/herddb-core/src/test/java/herddb/cluster/bookkeeper/BookieNotAvailableTest.java
index 7eea5411..9dbb4c11 100644
--- a/herddb-core/src/test/java/herddb/cluster/bookkeeper/BookieNotAvailableTest.java
+++ b/herddb-core/src/test/java/herddb/cluster/bookkeeper/BookieNotAvailableTest.java
@@ -49,6 +49,7 @@ import org.apache.bookkeeper.client.BookKeeper;
 import org.apache.bookkeeper.client.BookKeeperAdmin;
 import org.apache.bookkeeper.client.LedgerHandle;
 import org.apache.bookkeeper.client.api.LedgerMetadata;
+import org.apache.bookkeeper.net.BookieId;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -201,7 +202,7 @@ public class BookieNotAvailableTest extends BookkeeperFailuresBase {
             // we do not want auto-recovery
             server.getManager().setActivatorPauseStatus(true);
 
-            String bookieAddr = testEnv.stopBookie();
+            BookieId bookieAddr = testEnv.stopBookie();
 
             // transaction will continue and see the failure only the time of the commit
             try {
diff --git a/herddb-core/src/test/java/herddb/cluster/bookkeeper/MultiBookieTest.java b/herddb-core/src/test/java/herddb/cluster/bookkeeper/MultiBookieTest.java
index 5523c011..e22b8915 100644
--- a/herddb-core/src/test/java/herddb/cluster/bookkeeper/MultiBookieTest.java
+++ b/herddb-core/src/test/java/herddb/cluster/bookkeeper/MultiBookieTest.java
@@ -46,7 +46,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
-import org.apache.bookkeeper.net.BookieSocketAddress;
+import org.apache.bookkeeper.net.BookieId;
 import org.junit.Test;
 
 public class MultiBookieTest extends BookkeeperFailuresBase {
@@ -66,7 +66,7 @@ public class MultiBookieTest extends BookkeeperFailuresBase {
         serverconfig_1.set(ServerConfiguration.PROPERTY_BOOKKEEPER_WRITEQUORUMSIZE, 2);
         serverconfig_1.set(ServerConfiguration.PROPERTY_BOOKKEEPER_ACKQUORUMSIZE, 2);
 
-        List<BookieSocketAddress> bookies;
+        List<BookieId> bookies;
         try (Server server_1 = new Server(serverconfig_1)) {
             server_1.start();
             server_1.waitForStandaloneBoot();
@@ -113,10 +113,8 @@ public class MultiBookieTest extends BookkeeperFailuresBase {
         // pause one bookie and boot a new follower server
         // leader is offline, it must read the log
         // we must be able to recover even if one bookie is down
-        for (BookieSocketAddress bAddress : bookies) {
-            String bookieAddress = bAddress.getSocketAddress().toString();
-            System.out.println("PAUSING " + bookieAddress);
-            this.testEnv.pauseBookie(bookieAddress);
+        for (BookieId bAddress : bookies) {
+            this.testEnv.pauseBookie(bAddress);
 
             ServerConfiguration serverconfig_2 = serverconfig_1
                     .copy()
@@ -134,17 +132,15 @@ public class MultiBookieTest extends BookkeeperFailuresBase {
                         TransactionContext.NO_TRANSACTION).found());
             }
 
-            this.testEnv.resumeBookie(bookieAddress);
+            this.testEnv.resumeBookie(bAddress);
         }
 //
 
         // stop one bookie and boot a new follower server
         // leader is offline, it must read the log
         // we must be able to recover even if one bookie is down
-        for (BookieSocketAddress bAddress : bookies) {
-            String bookieAddress = bAddress.getSocketAddress().toString();
-            System.out.println("STOPPING " + bookieAddress);
-            this.testEnv.stopBookie(bookieAddress);
+        for (BookieId bAddress : bookies) {
+            this.testEnv.stopBookie(bAddress);
 
             ServerConfiguration serverconfig_2 = serverconfig_1
                     .copy()
@@ -162,7 +158,7 @@ public class MultiBookieTest extends BookkeeperFailuresBase {
                         TransactionContext.NO_TRANSACTION).found());
             }
 
-            this.testEnv.startStoppedBookie(bookieAddress);
+            this.testEnv.startStoppedBookie(bAddress);
         }
     }
 }
diff --git a/herddb-core/src/test/java/herddb/server/EmbeddedBookieTest.java b/herddb-core/src/test/java/herddb/server/EmbeddedBookieTest.java
index 7725b851..eb97b929 100644
--- a/herddb-core/src/test/java/herddb/server/EmbeddedBookieTest.java
+++ b/herddb-core/src/test/java/herddb/server/EmbeddedBookieTest.java
@@ -22,6 +22,7 @@ package herddb.server;
 
 import static herddb.core.TestUtils.newServerConfigurationWithAutoPort;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import herddb.client.ClientConfiguration;
@@ -78,25 +79,50 @@ public class EmbeddedBookieTest {
     }
 
     @Test
-    public void test_boot_with_bookie() throws Exception {
+    public void testBootWithBookieNoBookieId() throws Exception {
+        testBootWithBookie(false, false);
+    }
+
+    @Test
+    public void testBootWithBookieAndBookieId() throws Exception {
+        testBootWithBookie(true, false);
+    }
+
+    @Test
+    public void testBootWithBookieAndBookieIdAndAutomaticNodeId() throws Exception {
+        testBootWithBookie(true, true);
+    }
+
+    private void testBootWithBookie(boolean useBookiedId, boolean automaticNodeId) throws Exception {
         ServerConfiguration serverconfig_1 = newServerConfigurationWithAutoPort(folder.newFolder("server1").toPath());
-        serverconfig_1.set(ServerConfiguration.PROPERTY_NODEID, "server1");
+        if (!automaticNodeId) {
+            serverconfig_1.set(ServerConfiguration.PROPERTY_NODEID, "server1");
+        }
         serverconfig_1.set(ServerConfiguration.PROPERTY_MODE, ServerConfiguration.PROPERTY_MODE_CLUSTER);
         serverconfig_1.set(ServerConfiguration.PROPERTY_ZOOKEEPER_ADDRESS, testEnv.getAddress());
         serverconfig_1.set(ServerConfiguration.PROPERTY_ZOOKEEPER_PATH, testEnv.getPath());
         serverconfig_1.set(ServerConfiguration.PROPERTY_ZOOKEEPER_SESSIONTIMEOUT, testEnv.getTimeout());
         serverconfig_1.set(ServerConfiguration.PROPERTY_BOOKKEEPER_START, true);
+        serverconfig_1.set(ServerConfiguration.PROPERTY_BOOKKEEPER_BOOKIE_PORT, 0);
+        serverconfig_1.set(ServerConfiguration.PROPERTY_BOOKKEEPER_BOOKIE_BOOKIEID_ENABLED, useBookiedId);
         serverconfig_1.set("bookie.allowLoopback", true);
 
         ServerConfiguration serverconfig_2 = serverconfig_1
                 .copy()
                 .set(ServerConfiguration.PROPERTY_NODEID, "server2")
-                .set(ServerConfiguration.PROPERTY_BASEDIR, folder.newFolder("server2").toPath().toAbsolutePath())
-                .set(ServerConfiguration.PROPERTY_BOOKKEEPER_BOOKIE_PORT, 3182);
+                .set(ServerConfiguration.PROPERTY_BASEDIR, folder.newFolder("server2").toPath().toAbsolutePath());
 
         try (Server server_1 = new Server(serverconfig_1)) {
             server_1.start();
+            if (automaticNodeId) {
+                assertNotEquals("server1", server_1.getNodeId());
+            } else {
+                assertEquals("server1", server_1.getNodeId());
+            }
             server_1.waitForStandaloneBoot();
+            if (useBookiedId) {
+                assertEquals(server_1.getEmbeddedBookie().getBookieId(), server_1.getNodeId());
+            }
             Table table = Table.builder()
                     .name("t1")
                     .column("c", ColumnTypes.INTEGER)
@@ -110,7 +136,7 @@ public class EmbeddedBookieTest {
                 server_2.start();
 
                 server_1.getManager().executeStatement(new AlterTableSpaceStatement(TableSpace.DEFAULT,
-                        new HashSet<>(Arrays.asList("server1", "server2")), "server1", 1, 0), StatementEvaluationContext.DEFAULT_EVALUATION_CONTEXT(), TransactionContext.NO_TRANSACTION);
+                        new HashSet<>(Arrays.asList(server_1.getNodeId(), server_2.getNodeId())), server_1.getNodeId(), 1, 0), StatementEvaluationContext.DEFAULT_EVALUATION_CONTEXT(), TransactionContext.NO_TRANSACTION);
 
                 assertTrue(server_2.getManager().waitForTablespace(TableSpace.DEFAULT, 60000, false));
 
@@ -143,7 +169,7 @@ public class EmbeddedBookieTest {
                     }
                     // switch leader to server2
                     server_2.getManager().executeStatement(new AlterTableSpaceStatement(TableSpace.DEFAULT,
-                            new HashSet<>(Arrays.asList("server1", "server2")), "server2", 1, 0), StatementEvaluationContext.DEFAULT_EVALUATION_CONTEXT(), TransactionContext.NO_TRANSACTION);
+                            new HashSet<>(Arrays.asList(server_1.getNodeId(), server_2.getNodeId())), server_2.getNodeId(), 1, 0), StatementEvaluationContext.DEFAULT_EVALUATION_CONTEXT(), TransactionContext.NO_TRANSACTION);
 
                     // wait that server_1 leaves leadership
                     for (int i = 0; i < 100; i++) {
diff --git a/herddb-core/src/test/java/herddb/utils/ZKTestEnv.java b/herddb-core/src/test/java/herddb/utils/ZKTestEnv.java
index 6bc2b36d..c286036c 100644
--- a/herddb-core/src/test/java/herddb/utils/ZKTestEnv.java
+++ b/herddb-core/src/test/java/herddb/utils/ZKTestEnv.java
@@ -27,6 +27,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 import org.apache.bookkeeper.client.BookKeeperAdmin;
 import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.net.BookieId;
 import org.apache.bookkeeper.proto.BookieServer;
 import org.apache.bookkeeper.zookeeper.ZooKeeperClient;
 import org.apache.curator.test.TestingServer;
@@ -68,11 +69,11 @@ public class ZKTestEnv implements AutoCloseable {
         startBookie(true);
     }
 
-    public String startNewBookie() throws Exception {
+    public BookieId startNewBookie() throws Exception {
         return startBookie(false);
     }
 
-    private String startBookie(boolean format) throws Exception {
+    private BookieId startBookie(boolean format) throws Exception {
         if (format && !bookies.isEmpty()) {
             throw new Exception("cannot format, you aleady have bookies");
         }
@@ -86,7 +87,7 @@ public class ZKTestEnv implements AutoCloseable {
         BookieServer bookie = new BookieServer(conf);
         bookies.add(bookie);
         bookie.start();
-        return bookie.getLocalAddress().getSocketAddress().toString();
+        return bookie.getBookieId();
     }
 
     private ServerConfiguration createBookieConf(int port) {
@@ -116,10 +117,10 @@ public class ZKTestEnv implements AutoCloseable {
         return conf;
     }
 
-    public void startStoppedBookie(String addr) throws Exception {
+    public void startStoppedBookie(BookieId addr) throws Exception {
         int index = 0;
         for (BookieServer bookie : bookies) {
-            if (bookie.getLocalAddress().getSocketAddress().toString().equals(addr)) {
+            if (bookie.getBookieId().equals(addr)) {
                 if (bookie.isRunning()) {
                     throw new Exception("you did not stop bookie " + addr);
                 }
@@ -138,9 +139,9 @@ public class ZKTestEnv implements AutoCloseable {
         bookies.get(0).suspendProcessing();
     }
 
-    public void pauseBookie(String addr) throws Exception {
+    public void pauseBookie(BookieId addr) throws Exception {
         for (BookieServer bookie : bookies) {
-            if (bookie.getLocalAddress().getSocketAddress().toString().equals(addr)) {
+            if (bookie.getBookieId().equals(addr)) {
                 bookie.suspendProcessing();
                 return;
             }
@@ -152,9 +153,9 @@ public class ZKTestEnv implements AutoCloseable {
         bookies.get(0).resumeProcessing();
     }
 
-    public void resumeBookie(String addr) throws Exception {
+    public void resumeBookie(BookieId addr) throws Exception {
         for (BookieServer bookie : bookies) {
-            if (bookie.getLocalAddress().getSocketAddress().toString().equals(addr)) {
+            if (bookie.getBookieId().equals(addr)) {
                 bookie.resumeProcessing();
                 return;
             }
@@ -162,15 +163,15 @@ public class ZKTestEnv implements AutoCloseable {
         throw new Exception("Cannot find bookie " + addr);
     }
 
-    public String stopBookie() throws Exception {
-        String addr = bookies.get(0).getLocalAddress().getSocketAddress().toString();
+    public BookieId stopBookie() throws Exception {
+        BookieId addr = bookies.get(0).getBookieId();
         stopBookie(addr);
         return addr;
     }
 
-    public void stopBookie(String addr) throws Exception {
+    public void stopBookie(BookieId addr) throws Exception {
         for (BookieServer bookie : bookies) {
-            if (bookie.getLocalAddress().getSocketAddress().toString().equals(addr)) {
+            if (bookie.getBookieId().equals(addr)) {
                 bookie.shutdown();
                 bookie.join();
                 return;