List:Commits« Previous MessageNext Message »
From:Magnus Svensson Date:October 27 2008 11:13am
Subject:bzr commit into mysql-5.1 branch (msvensson:3018) WL#4350
View as plain text  
#At file:///home/msvensson/mysql/6.4/

 3018 Magnus Svensson	2008-10-27 [merge]
      Merge in WL#4350
removed:
  storage/ndb/include/kernel/signaldata/ManagementServer.hpp
  storage/ndb/src/mgmsrv/MgmtSrvrConfig.cpp
added:
  storage/ndb/include/kernel/signaldata/ConfigChange.hpp
  storage/ndb/src/common/debugger/signaldata/ApiVersion.cpp
  storage/ndb/src/mgmsrv/ConfigManager.cpp
  storage/ndb/src/mgmsrv/ConfigManager.hpp
  storage/ndb/src/mgmsrv/ConfigSubscriber.hpp
  storage/ndb/src/mgmsrv/DirIterator.cpp
  storage/ndb/src/mgmsrv/DirIterator.hpp
  storage/ndb/src/mgmsrv/MgmtThread.hpp
modified:
  mysql-test/mysql-test-run.pl
  mysql-test/suite/ndb/r/ndb_config.result
  mysql-test/suite/ndb/r/ndb_config2.result
  storage/ndb/include/kernel/BlockNumbers.h
  storage/ndb/include/kernel/GlobalSignalNumbers.h
  storage/ndb/include/kernel/signaldata/ApiVersion.hpp
  storage/ndb/include/kernel/signaldata/SignalData.hpp
  storage/ndb/include/mgmcommon/ConfigRetriever.hpp
  storage/ndb/src/common/debugger/signaldata/CMakeLists.txt
  storage/ndb/src/common/debugger/signaldata/Makefile.am
  storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp
  storage/ndb/src/common/debugger/signaldata/SignalNames.cpp
  storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp
  storage/ndb/src/kernel/vm/Configuration.cpp
  storage/ndb/src/mgmsrv/CMakeLists.txt
  storage/ndb/src/mgmsrv/Config.cpp
  storage/ndb/src/mgmsrv/Config.hpp
  storage/ndb/src/mgmsrv/ConfigInfo.cpp
  storage/ndb/src/mgmsrv/ConfigInfo.hpp
  storage/ndb/src/mgmsrv/InitConfigFileParser.cpp
  storage/ndb/src/mgmsrv/Makefile.am
  storage/ndb/src/mgmsrv/MgmtSrvr.cpp
  storage/ndb/src/mgmsrv/MgmtSrvr.hpp
  storage/ndb/src/mgmsrv/Services.cpp
  storage/ndb/src/mgmsrv/main.cpp
  storage/ndb/src/ndbapi/ClusterMgr.cpp
  storage/ndb/src/ndbapi/SignalSender.cpp
  storage/ndb/src/ndbapi/SignalSender.hpp
  storage/ndb/src/ndbapi/TransporterFacade.cpp
  storage/ndb/src/ndbapi/TransporterFacade.hpp
  storage/ndb/test/run-test/Makefile.am

=== modified file 'mysql-test/mysql-test-run.pl'
--- a/mysql-test/mysql-test-run.pl	2008-10-21 14:56:15 +0000
+++ b/mysql-test/mysql-test-run.pl	2008-10-27 11:13:34 +0000
@@ -2832,6 +2832,8 @@ sub ndb_mgmd_start ($) {
   mtr_add_arg($args, "--core");
   mtr_add_arg($args, "--nodaemon");
   mtr_add_arg($args, "--config-file=%s", "$cluster->{'data_dir'}/config.ini");
+  mtr_add_arg($args, "--datadir=%s", "$cluster->{'data_dir'}");
+  mtr_add_arg($args, "--ndb-nodeid=%d", $cluster->{'nodes'} + 1);
 
 
   my $path_ndb_mgmd_log= "$cluster->{'data_dir'}/\l$cluster->{'name'}_ndb_mgmd.log";

=== modified file 'mysql-test/suite/ndb/r/ndb_config.result'
--- a/mysql-test/suite/ndb/r/ndb_config.result	2008-09-13 16:15:54 +0000
+++ b/mysql-test/suite/ndb/r/ndb_config.result	2008-10-21 12:41:59 +0000
@@ -8,7 +8,7 @@ ndb_mgmd,5,localhost,, mysqld,6,localhos
 ndb_mgmd,5,localhost mysqld,6, mysqld,7, mysqld,8, mysqld,9, mysqld,10, ndbd,1,localhost ndbd,2,localhost ndbd,3,localhost ndbd,4,localhost
 ndb_mgmd,6,localhost mysqld,1, mysqld,7, mysqld,8, mysqld,9, mysqld,10, ndbd,2,localhost ndbd,3,localhost ndbd,4,localhost ndbd,5,localhost
 ndb_mgmd,1,localhost ndb_mgmd,2,localhost mysqld,11, mysqld,12, mysqld,13, mysqld,14, mysqld,15, ndbd,3,localhost ndbd,4,localhost ndbd,5,localhost ndbd,6,localhost
-shm,3,4,35,3 shm,3,5,35,3 shm,3,6,35,3 shm,4,5,35,4 shm,4,6,35,4 shm,5,6,35,5 tcp,11,3,55,3 tcp,11,4,55,4 tcp,11,5,55,5 tcp,11,6,55,6 tcp,12,3,55,3 tcp,12,4,55,4 tcp,12,5,55,5 tcp,12,6,55,6 tcp,13,3,55,3 tcp,13,4,55,4 tcp,13,5,55,5 tcp,13,6,55,6 tcp,14,3,55,3 tcp,14,4,55,4 tcp,14,5,55,5 tcp,14,6,55,6 tcp,15,3,55,3 tcp,15,4,55,4 tcp,15,5,55,5 tcp,15,6,55,6 tcp,1,3,55,1 tcp,1,4,55,1 tcp,1,5,55,1 tcp,1,6,55,1 tcp,2,3,55,2 tcp,2,4,55,2 tcp,2,5,55,2 tcp,2,6,55,2
+shm,3,4,35,3 shm,3,5,35,3 shm,3,6,35,3 shm,4,5,35,4 shm,4,6,35,4 shm,5,6,35,5 tcp,11,3,55,3 tcp,11,4,55,4 tcp,11,5,55,5 tcp,11,6,55,6 tcp,12,3,55,3 tcp,12,4,55,4 tcp,12,5,55,5 tcp,12,6,55,6 tcp,13,3,55,3 tcp,13,4,55,4 tcp,13,5,55,5 tcp,13,6,55,6 tcp,14,3,55,3 tcp,14,4,55,4 tcp,14,5,55,5 tcp,14,6,55,6 tcp,15,3,55,3 tcp,15,4,55,4 tcp,15,5,55,5 tcp,15,6,55,6 tcp,1,3,55,1 tcp,1,4,55,1 tcp,1,5,55,1 tcp,1,6,55,1 tcp,2,3,55,2 tcp,2,4,55,2 tcp,2,5,55,2 tcp,2,6,55,2 tcp,1,2,55,2
 3 1 2
 
 3 1 2

=== modified file 'mysql-test/suite/ndb/r/ndb_config2.result'
--- a/mysql-test/suite/ndb/r/ndb_config2.result	2007-06-27 12:28:02 +0000
+++ b/mysql-test/suite/ndb/r/ndb_config2.result	2008-10-21 12:41:59 +0000
@@ -1 +1 @@
-shm,3,4,35,3 shm,3,5,35,3 shm,3,6,35,3 shm,4,5,35,4 shm,4,6,35,4 shm,5,6,35,5 tcp,11,3,55,3 tcp,11,4,55,4 tcp,11,5,55,5 tcp,11,6,55,6 tcp,12,3,55,3 tcp,12,4,55,4 tcp,12,5,55,5 tcp,12,6,55,6 tcp,13,3,55,3 tcp,13,4,55,4 tcp,13,5,55,5 tcp,13,6,55,6 tcp,14,3,55,3 tcp,14,4,55,4 tcp,14,5,55,5 tcp,14,6,55,6 tcp,15,3,55,3 tcp,15,4,55,4 tcp,15,5,55,5 tcp,15,6,55,6 tcp,1,3,55,1 tcp,1,4,55,1 tcp,1,5,55,1 tcp,1,6,55,1 tcp,2,3,55,2 tcp,2,4,55,2 tcp,2,5,55,2 tcp,2,6,55,2
+shm,3,4,35,3 shm,3,5,35,3 shm,3,6,35,3 shm,4,5,35,4 shm,4,6,35,4 shm,5,6,35,5 tcp,11,3,55,3 tcp,11,4,55,4 tcp,11,5,55,5 tcp,11,6,55,6 tcp,12,3,55,3 tcp,12,4,55,4 tcp,12,5,55,5 tcp,12,6,55,6 tcp,13,3,55,3 tcp,13,4,55,4 tcp,13,5,55,5 tcp,13,6,55,6 tcp,14,3,55,3 tcp,14,4,55,4 tcp,14,5,55,5 tcp,14,6,55,6 tcp,15,3,55,3 tcp,15,4,55,4 tcp,15,5,55,5 tcp,15,6,55,6 tcp,1,3,55,1 tcp,1,4,55,1 tcp,1,5,55,1 tcp,1,6,55,1 tcp,2,3,55,2 tcp,2,4,55,2 tcp,2,5,55,2 tcp,2,6,55,2 tcp,1,2,55,2

=== modified file 'storage/ndb/include/kernel/BlockNumbers.h'
--- a/storage/ndb/include/kernel/BlockNumbers.h	2008-10-05 07:12:42 +0000
+++ b/storage/ndb/include/kernel/BlockNumbers.h	2008-10-27 11:13:34 +0000
@@ -19,7 +19,7 @@
 #include <kernel_types.h>
 #include <RefConvert.hpp>
 
-/* 240 */
+/* 32768 */
 #define MIN_API_BLOCK_NO  0x8000
 
 /* 2047 */
@@ -28,6 +28,14 @@
 /* 4002 */
 #define API_CLUSTERMGR 0x0FA2
 
+/* Fixed block numbers in API */
+#define NO_API_FIXED_BLOCKS    1
+#define MIN_API_FIXED_BLOCK_NO (API_CLUSTERMGR+1)
+#define MGM_CONFIG_MAN MIN_API_FIXED_BLOCK_NO
+
+#define MAX_API_FIXED_BLOCK_NO (MIN_API_FIXED_BLOCK_NO + NO_API_FIXED_BLOCKS)
+
+
 #define BACKUP      0xF4
 #define DBTC        0xF5
 #define DBDIH       0xF6

=== modified file 'storage/ndb/include/kernel/GlobalSignalNumbers.h'
--- a/storage/ndb/include/kernel/GlobalSignalNumbers.h	2008-10-05 07:14:37 +0000
+++ b/storage/ndb/include/kernel/GlobalSignalNumbers.h	2008-10-27 11:13:34 +0000
@@ -96,15 +96,19 @@ extern const GlobalSignalNumber NO_OF_SI
 #define GSN_DBINFO_SCANCONF             42
 #define GSN_DBINFO_SCANREF              43
 #define GSN_DBINFO_TRANSID_AI           44
-/* 45 unused */
-/* 46 unused */
-/* 47 unused */
-/* 48 unused */
-/* 49 unused */
-/* 50 unused */
-/* 51 unused */
-/* 52 unused */
-/* 53 unused */
+
+#define GSN_CONFIG_CHANGE_REQ           45
+#define GSN_CONFIG_CHANGE_REF           46
+#define GSN_CONFIG_CHANGE_CONF          47
+
+#define GSN_CONFIG_CHANGE_IMPL_REQ      48
+#define GSN_CONFIG_CHANGE_IMPL_REF      49
+#define GSN_CONFIG_CHANGE_IMPL_CONF     50
+
+#define GSN_CONFIG_CHECK_REQ            51
+#define GSN_CONFIG_CHECK_REF            52
+#define GSN_CONFIG_CHECK_CONF           53
+
 /* 54 unused */
 /* 55 unused */
 /* 56 unused */

=== modified file 'storage/ndb/include/kernel/signaldata/ApiVersion.hpp'
--- a/storage/ndb/include/kernel/signaldata/ApiVersion.hpp	2007-01-06 00:21:39 +0000
+++ b/storage/ndb/include/kernel/signaldata/ApiVersion.hpp	2008-10-24 12:51:04 +0000
@@ -16,19 +16,24 @@
 #ifndef API_VERSION_HPP
 #define API_VERSION_HPP
 
+#include "SignalData.hpp"
+
 class ApiVersionReq {
 /**
    * Sender(s)
    */
-  friend class MgmtSrv;
-  
+  friend class MgmtSrvr;
+
   /**
    * Reciver(s)
    */
-  friend class Qmgr;  
-public:
+  friend class Qmgr;
+
+  friend bool printAPI_VERSION_REQ(FILE *, const Uint32 *, Uint32, Uint16);
+
   STATIC_CONST( SignalLength = 4 );
-  Uint32 senderRef; 
+
+  Uint32 senderRef;
   Uint32 nodeId; //api node id
   Uint32 version; // Version of API node
   Uint32 mysql_version; // MySQL version
@@ -41,14 +46,17 @@ class ApiVersionConf {
    * Sender(s)
    */
   friend class Qmgr;
-  
+
   /**
    * Reciver(s)
    */
-  friend class MgmtSrv;  
-public:
+  friend class MgmtSrvr;
+
+  friend bool printAPI_VERSION_CONF(FILE *, const Uint32 *, Uint32, Uint16);
+
   STATIC_CONST( SignalLength = 5 );
-  Uint32 senderRef; 
+
+  Uint32 senderRef;
   Uint32 nodeId; //api node id
   Uint32 version; // Version of API node
   Uint32 inet_addr;

=== added file 'storage/ndb/include/kernel/signaldata/ConfigChange.hpp'
--- a/storage/ndb/include/kernel/signaldata/ConfigChange.hpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/include/kernel/signaldata/ConfigChange.hpp	2008-10-21 12:41:59 +0000
@@ -0,0 +1,253 @@
+/* Copyright (C) 2008 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef CONFIG_CHANGE_H
+#define CONFIG_CHANGE_H
+
+#include "SignalData.hpp"
+
+class ConfigChangeReq {
+  /**
+   * Sender
+   */
+  friend class MgmtSrvr;
+
+  /**
+   * Receiver
+   */
+  friend class ConfigManager;
+
+public:
+  STATIC_CONST( SignalLength = 1 );
+
+private:
+  Uint32 length; // Length of the config data in long signal
+};
+
+
+class ConfigChangeConf {
+  /**
+   * Sender
+   */
+  friend class ConfigManager;
+
+  /**
+   * Receiver
+   */
+  friend class MgmtSrvr;
+
+public:
+  STATIC_CONST( SignalLength = 1 );
+
+private:
+
+  Uint32 unused;
+};
+
+
+class ConfigChangeRef {
+  /**
+   * Sender
+   */
+  friend class ConfigManager;
+
+  /**
+   * Receiver
+   */
+  friend class MgmtSrvr;
+
+
+  enum ErrorCode {
+    OK                      = 0,
+    ConfigChangeOnGoing     = 1,
+    NotMaster               = 2,
+    NoConfigData            = 3,
+    ConfigChangeAborted     = 4,
+    FailedToStart           = 5,
+    SetGenerationFailed     = 10,
+    PrepareFailed           = 11,
+    IllegalConfigChange     = 13,
+    FailedToUnpack          = 14,
+    InvalidGeneration       = 15,
+    InvalidConfigName       = 16,
+    IllegalState            = 17,
+    IllegalInitialGeneration = 18,
+    DifferentInitial        = 19,
+    NotAllStarted           = 20
+  } ;
+
+public:
+  STATIC_CONST( SignalLength = 1 );
+
+  static const char* errorMessage(Uint32 error) {
+    switch (error){
+    case NoConfigData:
+      return "No config data in signal";
+    case ConfigChangeAborted:
+      return "Config change was aborted";
+    case FailedToStart:
+      return "Failed to start config change";
+    case SetGenerationFailed:
+      return "setGeneration failed";
+    case FailedToUnpack:
+      return "Failed to unpack the configuration";
+    case IllegalConfigChange:
+      return "Illegal config change";
+
+    default:
+      return "ConfigChangeRef, unknown error";
+    }
+  }
+
+private:
+
+  Uint32 errorCode;
+};
+
+
+class ConfigChangeImplReq {
+  /**
+   * Receiver and sender
+   */
+  friend class ConfigManager;
+
+  enum RequestType {
+    Prepare,
+    Commit,
+    Abort
+  };
+
+public:
+  STATIC_CONST( SignalLength = 3 );
+
+private:
+
+  Uint32 requestType;
+  Uint32 initial; // Valid when requestType = Prepare
+  Uint32 length; // Length of the config data in long signal
+};
+
+
+class ConfigChangeImplConf  {
+  /**
+   * Receiver and sender
+   */
+  friend class ConfigManager;
+
+public:
+  STATIC_CONST( SignalLength = 1 );
+
+private:
+
+  Uint32 requestType;
+};
+
+
+class ConfigChangeImplRef  {
+  /**
+   * Receiver and sender
+   */
+  friend class ConfigManager;
+
+public:
+  STATIC_CONST( SignalLength = 1 );
+
+private:
+
+  Uint32 errorCode;
+};
+
+
+class ConfigCheckReq  {
+  /**
+   * Sender
+   */
+  friend class MgmtSrvr;
+
+  /**
+   * Receiver
+   */
+  friend class ConfigManager;
+
+public:
+  STATIC_CONST( SignalLength = 2 );
+
+private:
+  Uint32 state;
+  Uint32 generation;
+};
+
+
+class ConfigCheckConf {
+  /**
+   * Sender
+   */
+  friend class ConfigManager;
+
+  /**
+   * Receiver
+   */
+  friend class MgmtSrvr;
+
+public:
+  STATIC_CONST( SignalLength = 2 );
+
+private:
+
+  Uint32 state;
+  Uint32 generation;
+};
+
+
+class ConfigCheckRef  {
+  /**
+   * Sender
+   */
+  friend class ConfigManager;
+
+  /**
+   * Receiver
+   */
+  friend class MgmtSrvr;
+
+  enum ErrorCode {
+    WrongState                 = 1,
+    WrongGeneration            = 2
+  };
+
+  static const char* errorMessage(Uint32 error) {
+    switch (error){
+    case WrongState:
+      return "Wrong state";
+    case WrongGeneration:
+      return "Wrong generation";
+
+    default:
+      return "ConfigCheckRef, unknown error";
+    }
+  }
+
+public:
+  STATIC_CONST( SignalLength = 5 );
+private:
+  Uint32 error;
+  Uint32 generation;
+  Uint32 expected_generation;
+  Uint32 state;
+  Uint32 expected_state;
+};
+
+
+#endif

=== removed file 'storage/ndb/include/kernel/signaldata/ManagementServer.hpp'
--- a/storage/ndb/include/kernel/signaldata/ManagementServer.hpp	2006-12-23 19:20:40 +0000
+++ b/storage/ndb/include/kernel/signaldata/ManagementServer.hpp	1970-01-01 00:00:00 +0000
@@ -1,86 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; version 2 of the License.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-
-#ifndef MANAGEMENTSERVER_HPP
-#define MANAGEMENTSERVER_HPP
-
-#include "SignalData.hpp"
-
-/**
- * Request to lock configuration
- */
-class MgmLockConfigReq {
-  friend class MgmtSrvr;
-
-public:
-  STATIC_CONST( SignalLength = 1 );
-
-private:
-  Uint32 newConfigGeneration;
-};
-
-/**
- * Confirm configuration lock
- */
-class MgmLockConfigRep {
-  friend class MgmtSrvr;
-public:
-  STATIC_CONST( SignalLength = 1 );
-
-  /* Error codes */
-  enum ErrorCode {
-    OK,
-    UNKNOWN_ERROR,
-    GENERATION_MISMATCH,
-    ALREADY_LOCKED
-  };
-
-private:
-  Uint32 errorCode;
-};
-
-/**
- * Unlock configuration
- */
-class MgmUnlockConfigReq {
-  friend class MgmtSrvr;
-
-public:
-  STATIC_CONST( SignalLength = 1 );
-
-private:
-  Uint32 commitConfig;
-};
-
-/**
- * Confirm config unlock
- */
-class MgmUnlockConfigRep {
-  friend class MgmtSrvr;
-public:
-  STATIC_CONST( SignalLength = 1 );
-
-  /* Error codes */
-  enum ErrorCode {
-    OK,
-    UNKNOWN_ERROR,
-    NOT_LOCKED
-  };
-
-private:
-  Uint32 errorCode;
-};
-
-#endif /* !MANAGEMENTSERVER_HPP */

=== modified file 'storage/ndb/include/kernel/signaldata/SignalData.hpp'
--- a/storage/ndb/include/kernel/signaldata/SignalData.hpp	2007-12-25 16:34:29 +0000
+++ b/storage/ndb/include/kernel/signaldata/SignalData.hpp	2008-10-24 12:51:04 +0000
@@ -273,4 +273,7 @@ GSN_PRINT_SIGNATURE(printBUILD_INDX_IMPL
 GSN_PRINT_SIGNATURE(printBUILD_INDX_IMPL_CONF);
 GSN_PRINT_SIGNATURE(printBUILD_INDX_IMPL_REF);
 
+GSN_PRINT_SIGNATURE(printAPI_VERSION_REQ);
+GSN_PRINT_SIGNATURE(printAPI_VERSION_CONF);
+
 #endif

=== modified file 'storage/ndb/include/mgmcommon/ConfigRetriever.hpp'
--- a/storage/ndb/include/mgmcommon/ConfigRetriever.hpp	2007-03-22 11:35:31 +0000
+++ b/storage/ndb/include/mgmcommon/ConfigRetriever.hpp	2008-10-24 10:06:10 +0000
@@ -34,7 +34,8 @@ public:
 
   int do_connect(int no_retries, int retry_delay_in_seconds, int verbose);
   int disconnect();
-  
+  bool is_connected();
+
   /**
    * Get configuration for current node.
    * 
@@ -90,9 +91,10 @@ private:
     CR_RETRY = 2
   };
   ErrorType latestErrorType;
-  
+
   void setError(ErrorType, const char * errorMsg);
-  
+  void setError(ErrorType, BaseString err);
+
   Uint32      _ownNodeId;
   bool m_end_session;
 

=== added file 'storage/ndb/src/common/debugger/signaldata/ApiVersion.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/ApiVersion.cpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/ApiVersion.cpp	2008-10-24 12:51:04 +0000
@@ -0,0 +1,50 @@
+/* Copyright (C) 2003 MySQL AB
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+
+#include <signaldata/ApiVersion.hpp>
+#include <RefConvert.hpp>
+
+bool
+printAPI_VERSION_REQ(FILE * output,
+                     const Uint32 * theData,
+                     Uint32 len,
+                     Uint16 recBlockNo){
+
+  ApiVersionReq * sig = (ApiVersionReq *)&theData[0];
+
+  fprintf(output,
+          " senderRef: (node: %d, block: %d), nodeId: %d\n" \
+          " version: %d, mysql_version: %d\n",
+	  refToNode(sig->senderRef), refToBlock(sig->senderRef),
+	  sig->nodeId, sig->version, sig->mysql_version);
+  return true;
+}
+
+bool
+printAPI_VERSION_CONF(FILE * output,
+                      const Uint32 * theData,
+                      Uint32 len,
+                      Uint16 recBlockNo){
+
+  ApiVersionConf * sig = (ApiVersionConf *)&theData[0];
+
+  fprintf(output,
+          " senderRef: (node: %d, block: %d), nodeId: %d\n" \
+          " version: %d, mysql_version: %d, inet_addr: %d\n",
+	  refToNode(sig->senderRef), refToBlock(sig->senderRef),
+	  sig->nodeId, sig->version, sig->mysql_version, sig->inet_addr);
+  return true;
+}

=== modified file 'storage/ndb/src/common/debugger/signaldata/CMakeLists.txt'
--- a/storage/ndb/src/common/debugger/signaldata/CMakeLists.txt	2008-08-22 00:22:44 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/CMakeLists.txt	2008-10-24 12:51:04 +0000
@@ -44,5 +44,5 @@ ADD_LIBRARY(ndbsignaldata STATIC
         SumaImpl.cpp NdbSttor.cpp CreateFragmentation.cpp
         UtilLock.cpp TuxMaint.cpp AccLock.cpp
         LqhTrans.cpp ReadNodesConf.cpp CntrStart.cpp
-        ScanFrag.cpp )
+        ScanFrag.cpp ApiVersion.cpp)
 

=== modified file 'storage/ndb/src/common/debugger/signaldata/Makefile.am'
--- a/storage/ndb/src/common/debugger/signaldata/Makefile.am	2008-08-26 14:20:06 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/Makefile.am	2008-10-24 12:51:04 +0000
@@ -45,7 +45,7 @@ libsignaldataprint_la_SOURCES = \
  	  CreateTab.cpp CreateTable.cpp DropTable.cpp \
   	  CreateTrigImpl.cpp DropTrigImpl.cpp \
  	  CreateIndxImpl.cpp DropIndxImpl.cpp AlterIndxImpl.cpp \
- 	  BuildIndx.cpp BuildIndxImpl.cpp
+ 	  BuildIndx.cpp BuildIndxImpl.cpp ApiVersion.cpp
 
 include $(top_srcdir)/storage/ndb/config/common.mk.am
 include $(top_srcdir)/storage/ndb/config/type_ndbapi.mk.am

=== modified file 'storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp	2008-02-06 20:10:07 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp	2008-10-24 12:51:04 +0000
@@ -244,6 +244,9 @@ SignalDataPrintFunctions[] = {
   ,{ GSN_BUILD_INDX_IMPL_CONF, printBUILD_INDX_IMPL_CONF }
   ,{ GSN_BUILD_INDX_IMPL_REF, printBUILD_INDX_IMPL_REF }
 
+  ,{ GSN_API_VERSION_REQ, printAPI_VERSION_REQ }
+  ,{ GSN_API_VERSION_CONF, printAPI_VERSION_CONF }
+
   ,{ 0, 0 }
 };
 

=== modified file 'storage/ndb/src/common/debugger/signaldata/SignalNames.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp	2008-09-12 12:55:29 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp	2008-10-21 12:41:59 +0000
@@ -709,5 +709,19 @@ const GsnName SignalNames [] = {
   ,{ GSN_DROP_NODEGROUP_IMPL_REQ, "DROP_NODEGROUP_IMPL_REQ" }
   ,{ GSN_DROP_NODEGROUP_IMPL_CONF, "DROP_NODEGROUP_IMPL_CONF" }
   ,{ GSN_DROP_NODEGROUP_IMPL_REF, "DROP_NODEGROUP_IMPL_REF" }
+
+  ,{ GSN_CONFIG_CHECK_REQ, "CONFIG_CHECK_REQ" }
+  ,{ GSN_CONFIG_CHECK_REF, "CONFIG_CHECK_REF" }
+  ,{ GSN_CONFIG_CHECK_CONF, "CONFIG_CHECK_CONF" }
+
+  ,{ GSN_CONFIG_CHANGE_REQ, "CONFIG_CHANGE_REQ" }
+  ,{ GSN_CONFIG_CHANGE_REF, "CONFIG_CHANGE_REF" }
+  ,{ GSN_CONFIG_CHANGE_CONF, "CONFIG_CHANGE_CONF" }
+
+  ,{ GSN_CONFIG_CHANGE_IMPL_REQ, "CONFIG_CHANGE_IMPL_REQ" }
+  ,{ GSN_CONFIG_CHANGE_IMPL_REF, "CONFIG_CHANGE_IMPL_REF" }
+  ,{ GSN_CONFIG_CHANGE_IMPL_CONF, "CONFIG_CHANGE_IMPL_CONF" }
+
+
 };
 const unsigned short NO_OF_SIGNAL_NAMES = sizeof(SignalNames)/sizeof(GsnName);

=== modified file 'storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp'
--- a/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp	2008-06-10 20:06:47 +0000
+++ b/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp	2008-10-24 10:06:10 +0000
@@ -29,10 +29,7 @@
 #include <Properties.hpp>
 
 #include <socket_io.h>
-#include <NdbConfig.h>
 
-#include <NdbAutoPtr.hpp>
- 
 #include <mgmapi.h>
 #include <mgmapi_config_parameters.h>
 #include <mgmapi_configuration.hpp>
@@ -48,6 +45,9 @@ ConfigRetriever::ConfigRetriever(const c
                                  int timeout_ms)
 {
   DBUG_ENTER("ConfigRetriever::ConfigRetriever");
+  DBUG_PRINT("enter", ("%s, version: %d, node_type: %d, bind: %s, timeout: %d",
+                       _connect_string, version, node_type,
+                       _bindaddress, timeout_ms));
 
   m_version = version;
   m_node_type = node_type;
@@ -137,6 +137,12 @@ ConfigRetriever::disconnect()
   return ndb_mgm_disconnect(m_handle);
 }
 
+bool
+ConfigRetriever::is_connected(void)
+{
+  return (ndb_mgm_is_connected(m_handle) != 0);
+}
+
 //****************************************************************************
 //****************************************************************************
 //****************************************************************************
@@ -177,49 +183,45 @@ ConfigRetriever::getConfig(NdbMgmHandle 
 }
 
 ndb_mgm_configuration *
-ConfigRetriever::getConfig(const char * filename){
-#ifndef NDB_WIN32	
-
-  struct stat sbuf;
-  const int res = stat(filename, &sbuf);
-  if(res != 0){
-    char buf[255];
-    BaseString::snprintf(buf, sizeof(buf), "Could not find file: \"%s\"", filename);
-    setError(CR_ERROR, buf);
+ConfigRetriever::getConfig(const char * filename)
+{
+  if (access(filename, F_OK))
+  {
+    BaseString err;
+    err.assfmt("Could not find file: '%s'", filename);
+    setError(CR_ERROR, err);
     return 0;
   }
-  const Uint32 bytes = sbuf.st_size;
-  
-  Uint32 * buf2 = new Uint32[bytes/4+1];
-  
+
   FILE * f = fopen(filename, "rb");
-  if(f == 0){
+  if(f == 0)
+  {
     setError(CR_ERROR, "Failed to open file");
-    delete []buf2;
     return 0;
   }
-  Uint32 sz = fread(buf2, 1, bytes, f);
-  fclose(f);
-  if(sz != bytes){
-    setError(CR_ERROR, "Failed to read file");
-    delete []buf2;
-    return 0;
+
+  size_t read_sz;
+  char read_buf[512];
+  UtilBuffer config_buf;
+  while ((read_sz = fread(read_buf, 1, sizeof(read_buf), f)) != 0)
+  {
+    if (config_buf.append(read_buf, read_sz) != 0)
+    {
+      setError(CR_ERROR, "Out of memory when appending read data");
+      fclose(f);
+      return 0;
+    }
   }
-  
+  fclose(f);
+
   ConfigValuesFactory cvf;
-  if(!cvf.unpack(buf2, bytes)){
-    char buf[255];
-    BaseString::snprintf(buf, sizeof(buf), "Error while unpacking"); 
-    setError(CR_ERROR, buf);
-    delete []buf2;
+  if(!cvf.unpack(config_buf))
+  {
+    setError(CR_ERROR,  "Error while unpacking");
     return 0;
   }
-  delete [] buf2;
-  return (ndb_mgm_configuration*)cvf.m_cfg;
-#else
-  return 0;
-#endif
-}			   
+  return (ndb_mgm_configuration*)cvf.getConfigValues();
+}
 
 void
 ConfigRetriever::setError(ErrorType et, const char * s){
@@ -228,6 +230,11 @@ ConfigRetriever::setError(ErrorType et, 
 }
 
 void
+ConfigRetriever::setError(ErrorType et, BaseString err){
+  setError(et, err.c_str());
+}
+
+void
 ConfigRetriever::resetError(){
   setError(CR_NO_ERROR,0);
 }
@@ -243,65 +250,57 @@ ConfigRetriever::getErrorString(){
   return errorString.c_str();
 }
 
-bool
-ConfigRetriever::verifyConfig(const struct ndb_mgm_configuration * conf, Uint32 nodeid){
 
+bool
+ConfigRetriever::verifyConfig(const struct ndb_mgm_configuration * conf,
+                              Uint32 nodeid)
+{
   char buf[255];
-  ndb_mgm_configuration_iterator * it;
-  it = ndb_mgm_create_configuration_iterator((struct ndb_mgm_configuration *)conf,
-					     CFG_SECTION_NODE);
+  ndb_mgm_configuration_iterator it(* conf, CFG_SECTION_NODE);
 
-  if(it == 0){
-    BaseString::snprintf(buf, 255, "Unable to create config iterator");
-    setError(CR_ERROR, buf);
-    return false;
-    
-  }
-  NdbAutoPtr<ndb_mgm_configuration_iterator> ptr(it);
-  
-  if(ndb_mgm_find(it, CFG_NODE_ID, nodeid) != 0){
+  if(it.find(CFG_NODE_ID, nodeid)){
     BaseString::snprintf(buf, 255, "Unable to find node with id: %d", nodeid);
     setError(CR_ERROR, buf);
     return false;
   }
-     
+
   const char * hostname;
-  if(ndb_mgm_get_string_parameter(it, CFG_NODE_HOST, &hostname)){
-    BaseString::snprintf(buf, 255, "Unable to get hostname(%d) from config",CFG_NODE_HOST);
+  if(it.get(CFG_NODE_HOST, &hostname)){
+    BaseString::snprintf(buf, 255, "Unable to get hostname(%d) from config",
+                         CFG_NODE_HOST);
     setError(CR_ERROR, buf);
     return false;
   }
 
-  const char * datadir;
-  if(!ndb_mgm_get_string_parameter(it, CFG_NODE_DATADIR, &datadir)){
-    NdbConfig_SetPath(datadir);
-  }
-
   if (hostname && hostname[0] != 0 &&
       !SocketServer::tryBind(0,hostname)) {
-    BaseString::snprintf(buf, 255, "Config hostname(%s) don't match a local interface,"
-	     " tried to bind, error = %d - %s",
-	     hostname, errno, strerror(errno));
+    BaseString::snprintf(buf, 255,
+                         "Config hostname: %s don't match a local "
+                         "interface, tried to bind, error: %d '%s'",
+                         hostname, errno, strerror(errno));
     setError(CR_ERROR, buf);
     return false;
   }
 
   unsigned int _type;
-  if(ndb_mgm_get_int_parameter(it, CFG_TYPE_OF_SECTION, &_type)){
+  if(it.get(CFG_TYPE_OF_SECTION, &_type)){
     BaseString::snprintf(buf, 255, "Unable to get type of node(%d) from config",
-	     CFG_TYPE_OF_SECTION);
+                         CFG_TYPE_OF_SECTION);
     setError(CR_ERROR, buf);
     return false;
   }
-  
+
   if(_type != m_node_type){
     const char *type_s, *alias_s, *type_s2, *alias_s2;
-    alias_s= ndb_mgm_get_node_type_alias_string((enum ndb_mgm_node_type)m_node_type,
-						&type_s);
-    alias_s2= ndb_mgm_get_node_type_alias_string((enum ndb_mgm_node_type)_type,
-						 &type_s2);
-    BaseString::snprintf(buf, 255, "This node type %s(%s) and config "
-			 "node type %s(%s) don't match for nodeid %d", 
+    alias_s=
+      ndb_mgm_get_node_type_alias_string((enum ndb_mgm_node_type)m_node_type,
+                                         &type_s);
+    alias_s2=
+      ndb_mgm_get_node_type_alias_string((enum ndb_mgm_node_type)_type,
+                                         &type_s2);
+    BaseString::snprintf(buf, 255,
+                         "This node type %s(%s) and config "
+			 "node type %s(%s) don't match for nodeid %d",
 			 alias_s, type_s, alias_s2, type_s2, nodeid);
     setError(CR_ERROR, buf);
     return false;
@@ -347,6 +346,7 @@ ConfigRetriever::verifyConfig(const stru
       }
     }
   }
+
   return true;
 }
 

=== modified file 'storage/ndb/src/kernel/vm/Configuration.cpp'
--- a/storage/ndb/src/kernel/vm/Configuration.cpp	2008-08-21 06:31:25 +0000
+++ b/storage/ndb/src/kernel/vm/Configuration.cpp	2008-10-21 12:41:59 +0000
@@ -26,6 +26,7 @@
 #include <NdbMem.h>
 #include <NdbOut.hpp>
 #include <WatchDog.hpp>
+#include <NdbConfig.h>
 
 #include <mgmapi_configuration.hpp>
 #include <mgmapi_config_parameters_debug.h>
@@ -338,6 +339,13 @@ Configuration::fetch_configuration(){
 	      "StopOnError missing");
   }
 
+  const char * datadir;
+  if(iter.get(CFG_NODE_DATADIR, &datadir)){
+    ERROR_SET(fatal, NDBD_EXIT_INVALID_CONFIG, "Invalid configuration fetched",
+	      "DataDir missing");
+  }
+  NdbConfig_SetPath(datadir);
+
   m_mgmds.clear();
   for(ndb_mgm_first(&iter); ndb_mgm_valid(&iter); ndb_mgm_next(&iter))
   {

=== modified file 'storage/ndb/src/mgmsrv/CMakeLists.txt'
--- a/storage/ndb/src/mgmsrv/CMakeLists.txt	2008-08-20 13:22:29 +0000
+++ b/storage/ndb/src/mgmsrv/CMakeLists.txt	2008-10-24 12:41:10 +0000
@@ -41,6 +41,6 @@ ADD_EXECUTABLE(ndb_mgmd
                MgmtSrvr.cpp
                main.cpp
                Services.cpp
-               MgmtSrvrConfig.cpp
-               ${CMAKE_SOURCE_DIR}/sql/nt_servc.cc)
+               ConfigManager.cpp
+               DirIterator.cpp)
 TARGET_LINK_LIBRARIES(ndb_mgmd ndbconf)

=== modified file 'storage/ndb/src/mgmsrv/Config.cpp'
--- a/storage/ndb/src/mgmsrv/Config.cpp	2008-09-16 09:37:22 +0000
+++ b/storage/ndb/src/mgmsrv/Config.cpp	2008-10-21 12:41:59 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003 MySQL AB
+/* Copyright (C) 2003-2008 MySQL AB, 2008 Sun Microsystems, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -19,14 +19,12 @@
 #include <NdbOut.hpp>
 #include "ConfigInfo.hpp"
 
-
 static void require(bool b)
 {
   if (!b)
     abort();
 }
 
-
 Config::Config(struct ndb_mgm_configuration *config_values) :
   m_configValues(config_values)
 {
@@ -38,6 +36,18 @@ Config::Config(ConfigValues *config_valu
 {
 }
 
+Config::Config(const Config* conf)
+{
+  // TODO Magnus, improve copy constructor
+  // to not use pack/unpack
+  assert(conf);
+  UtilBuffer buf;
+  conf->pack(buf);
+  ConfigValuesFactory cvf;
+  cvf.unpack(buf);
+  m_configValues= (struct ndb_mgm_configuration*)cvf.getConfigValues();
+}
+
 
 Config::~Config() {
   if(m_configValues != 0){
@@ -110,29 +120,44 @@ Config::getGeneration() const
 }
 
 
+const char*
+Config::getName() const
+{
+  const char* name;
+  ConfigIter iter(this, CFG_SECTION_SYSTEM);
+
+  if (iter.get(CFG_SYS_NAME, &name))
+    return 0;
+
+  return name;
+}
+
 
 bool
 Config::setValue(Uint32 section, Uint32 section_no,
                  Uint32 id, Uint32 new_val)
 {
   ConfigValues::Iterator iter(m_configValues->m_config);
-  if (iter.openSection(section, section_no)){
-    if (!iter.set(id, new_val))
-      return false;
-  }
-  else
-  {
-    ConfigValuesFactory cf(&m_configValues->m_config);
-    if (!cf.openSection(section, section_no))
-      return false;
-    if (!cf.put(CFG_TYPE_OF_SECTION, section))
-      return false;
-    if (!cf.put(id, new_val))
-      return false;
-    cf.closeSection();
+  if (!iter.openSection(section, section_no))
+    return false;
 
-    m_configValues= (struct ndb_mgm_configuration*)cf.getConfigValues();
-  }
+  if (!iter.set(id, new_val))
+    return false;
+
+  return true;
+}
+
+
+bool
+Config::setValue(Uint32 section, Uint32 section_no,
+                 Uint32 id, const char* new_val)
+{
+  ConfigValues::Iterator iter(m_configValues->m_config);
+  if (!iter.openSection(section, section_no))
+    return false;
+
+  if (!iter.set(id, new_val))
+    return false;
 
   return true;
 }
@@ -147,6 +172,15 @@ Config::setGeneration(Uint32 new_gen)
 }
 
 
+bool
+Config::setName(const char* new_name)
+{
+  return setValue(CFG_SECTION_SYSTEM, 0,
+                  CFG_SYS_NAME,
+                  new_name);
+}
+
+
 Uint32
 Config::pack(UtilBuffer& buf) const
 {
@@ -168,7 +202,6 @@ add_diff(const char* name, const char* k
          Properties& diff,
          const char* value_name, Properties* value)
 {
-
   Properties *section;
   // Create a new section if it did not exist
   if (!diff.getCopy(key, &section)){
@@ -187,7 +220,8 @@ add_diff(const char* name, const char* k
   require(value->get("Type", &type));
 
   // Add the value to the section if not already added
-  if (!section->put(value_name, value))
+  require(value->put("Name", value_name));
+  if (!section->put("Value", value))
     require(section->getPropertiesErrno() ==
             E_PROPERTIES_ELEMENT_ALREADY_EXISTS);
 
@@ -537,6 +571,7 @@ Config::diff2str(const Properties& diff_
 
       Uint32 type;
       require(what->get("Type", &type));
+      require(what->get("Name", &name));
       switch (type) {
       case DT_DIFF:
       {

=== modified file 'storage/ndb/src/mgmsrv/Config.hpp'
--- a/storage/ndb/src/mgmsrv/Config.hpp	2008-09-16 09:37:22 +0000
+++ b/storage/ndb/src/mgmsrv/Config.hpp	2008-10-21 12:41:59 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003 MySQL AB
+/* Copyright (C) 2003-2008 MySQL AB, 2008 Sun Microsystems, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -33,6 +33,7 @@ class Config {
 public:
   Config(struct ndb_mgm_configuration *config_values = NULL);
   Config(ConfigValues* config_values);
+  Config(const Config*);
   virtual ~Config();
 
   void print() const;
@@ -45,6 +46,12 @@ public:
   bool setGeneration(Uint32);
 
   /*
+    Returns name of the config
+  */
+  const char* getName() const;
+  bool setName(const char* new_name);
+
+  /*
    Pack the config into a UtilBuffer and return it's size in bytes
   */
   Uint32 pack(UtilBuffer&) const;
@@ -80,7 +87,9 @@ public:
 
 private:
   bool setValue(Uint32 section, Uint32 section_no,
-                Uint32 id, Uint32 new_gen);
+                Uint32 id, Uint32 new_val);
+  bool setValue(Uint32 section, Uint32 section_no,
+                Uint32 id, const char* new_val);
 
   bool illegal_change(const Properties&) const;
   bool equal(const Properties&) const;

=== modified file 'storage/ndb/src/mgmsrv/ConfigInfo.cpp'
--- a/storage/ndb/src/mgmsrv/ConfigInfo.cpp	2008-09-17 13:23:21 +0000
+++ b/storage/ndb/src/mgmsrv/ConfigInfo.cpp	2008-10-21 12:41:59 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003 MySQL AB
+/* Copyright (C) 2003-2008 MySQL AB, 2008 Sun Microsystems, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -191,6 +191,9 @@ const int ConfigInfo::m_NoOfRules = size
 /****************************************************************************
  * Config Rules declarations
  ****************************************************************************/
+static bool add_system_section(Vector<ConfigInfo::ConfigRuleSection>&sections,
+                               struct InitConfigFileParser::Context &ctx,
+                               const char * rule_data);
 static bool sanity_checks(Vector<ConfigInfo::ConfigRuleSection>&sections, 
 			  struct InitConfigFileParser::Context &ctx, 
 			  const char * rule_data);
@@ -211,11 +214,12 @@ static bool saveSectionsInConfigValues(V
 
 const ConfigInfo::ConfigRule 
 ConfigInfo::m_ConfigRules[] = {
+  { add_system_section, 0 },
   { sanity_checks, 0 },
   { add_node_connections, 0 },
   { set_connection_priorities, 0 },
   { check_node_vs_replicas, 0 },
-  { saveSectionsInConfigValues, "Node,Connection" },
+  { saveSectionsInConfigValues, "SYSTEM,Node,Connection" },
   { 0, 0 }
 };
 	  
@@ -348,6 +352,10 @@ const ConfigInfo::ParamInfo ConfigInfo::
     "0",
     STR_VALUE(MAX_INT_RNIL) },
 
+  /***************************************************************************
+   * DB
+   ***************************************************************************/
+
   {
     CFG_SYS_CONFIG_GENERATION,
     "ConfigGenerationNumber",
@@ -407,10 +415,7 @@ const ConfigInfo::ParamInfo ConfigInfo::
     "false",
     "false",
     "true"},
-  
-  /***************************************************************************
-   * DB
-   ***************************************************************************/
+
   {
     CFG_SECTION_NODE,
     DB_TOKEN,
@@ -1817,7 +1822,7 @@ const ConfigInfo::ParamInfo ConfigInfo::
     ConfigInfo::CI_USED,
     false,
     ConfigInfo::CI_STRING,
-    MYSQLCLUSTERDIR,
+    "",
     0, 0 },
 
   {
@@ -3237,8 +3242,6 @@ transformSystem(InitConfigFileParser::Co
     return false;
   }
 
-  ndbout << "transformSystem " << name << endl;
-
   BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "SYSTEM_%s", name);
   
   return true;
@@ -3976,6 +3979,42 @@ saveInConfigValues(InitConfigFileParser:
   return true;
 }
 
+
+static bool
+add_system_section(Vector<ConfigInfo::ConfigRuleSection>&sections,
+                   struct InitConfigFileParser::Context &ctx,
+                   const char * rule_data)
+{
+  if (!ctx.m_userProperties.contains("SYSTEM")) {
+    ConfigInfo::ConfigRuleSection s;
+
+    // Generate a unique name for this new cluster
+    time_t now = ::time((time_t*)NULL);
+    struct tm* tm_now = ::localtime(&now);
+
+    char name_buf[18];
+    BaseString::snprintf(name_buf, sizeof(name_buf),
+                         "MC_%d%.2d%.2d%.2d%.2d%.2d",
+                         tm_now->tm_year + 1900,
+                         tm_now->tm_mon + 1,
+                         tm_now->tm_mday,
+                         tm_now->tm_hour,
+                         tm_now->tm_min,
+                         tm_now->tm_sec);
+
+    s.m_sectionType = BaseString("SYSTEM");
+    s.m_sectionData = new Properties(true);
+    s.m_sectionData->put("Name", name_buf);
+    s.m_sectionData->put("Type", "SYSTEM");
+
+    // ndbout_c("Generated new SYSTEM section with name '%s'", name_buf);
+
+    sections.push_back(s);
+  }
+  return true;
+}
+
+
 static bool
 sanity_checks(Vector<ConfigInfo::ConfigRuleSection>&sections, 
 	      struct InitConfigFileParser::Context &ctx, 
@@ -4161,6 +4200,7 @@ add_node_connections(Vector<ConfigInfo::
 
   Uint32 nodeId1, nodeId2, dummy;
 
+  // DB -> DB
   for (i= 0; p_db_nodes.get("", i, &nodeId1); i++){
     for (Uint32 j= i+1;; j++){
       if(!p_db_nodes.get("", j, &nodeId2)) break;
@@ -4172,6 +4212,7 @@ add_node_connections(Vector<ConfigInfo::
     }
   }
 
+  // API -> DB
   for (i= 0; p_api_nodes.get("", i, &nodeId1); i++){
     if(!p_connections.get("", nodeId1, &dummy)) {
       for (Uint32 j= 0;; j++){
@@ -4182,6 +4223,7 @@ add_node_connections(Vector<ConfigInfo::
     }
   }
 
+  // MGM -> DB
   for (i= 0; p_mgm_nodes.get("", i, &nodeId1); i++){
     if(!p_connections.get("", nodeId1, &dummy)) {
       for (Uint32 j= 0;; j++){
@@ -4191,7 +4233,19 @@ add_node_connections(Vector<ConfigInfo::
       }
     }
   }
-  
+
+  // MGM -> MGM
+  for (i= 0; p_mgm_nodes.get("", i, &nodeId1); i++){
+    for (Uint32 j= i+1;; j++){
+      if(!p_mgm_nodes.get("", j, &nodeId2)) break;
+      if(!p_connections2.get("", nodeId1+nodeId2<<16, &dummy))
+      {
+	if (!add_a_connection(sections,ctx,nodeId1,nodeId2,0))
+	  goto err;
+     }
+    }
+  }
+
   DBUG_RETURN(true);
 err:
   DBUG_RETURN(false);

=== modified file 'storage/ndb/src/mgmsrv/ConfigInfo.hpp'
--- a/storage/ndb/src/mgmsrv/ConfigInfo.hpp	2008-07-25 10:02:59 +0000
+++ b/storage/ndb/src/mgmsrv/ConfigInfo.hpp	2008-10-21 12:41:59 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003 MySQL AB
+/* Copyright (C) 2003-2008 MySQL AB, 2008 Sun Microsystems, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by

=== added file 'storage/ndb/src/mgmsrv/ConfigManager.cpp'
--- a/storage/ndb/src/mgmsrv/ConfigManager.cpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/mgmsrv/ConfigManager.cpp	2008-10-24 12:41:10 +0000
@@ -0,0 +1,1557 @@
+/* Copyright (C) 2008 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+
+#include "ConfigManager.hpp"
+#include "MgmtSrvr.hpp"
+
+#include <NdbConfig.h>
+
+#include <SignalSender.hpp>
+#include <NdbApiSignal.hpp>
+#include <signaldata/NFCompleteRep.hpp>
+#include <signaldata/NodeFailRep.hpp>
+#include <signaldata/ApiRegSignalData.hpp>
+#include <ndb_version.h>
+
+
+#ifdef VM_TRACE
+#define require(v)  assert(v)
+#else
+static void
+require(bool v)
+{
+  if (!v)
+    abort();
+}
+#endif
+
+extern "C" const char* opt_connect_str;
+
+ConfigManager::ConfigManager(const MgmtSrvr::MgmtOpts& opts) :
+  MgmtThread("ConfigManager"),
+  m_opts(opts),
+  m_facade(NULL),
+  m_config_mutex(NULL),
+  m_config(NULL),
+  m_new_config(NULL),
+  m_config_retriever(opt_connect_str,
+                     NDB_VERSION,
+                     NDB_MGM_NODE_TYPE_MGM,
+                     opts.bind_address),
+  m_config_change_state(CCS_IDLE),
+  m_config_state(CS_UNINITIALIZED),
+  m_previous_state(CS_UNINITIALIZED),
+  m_client_ref(RNIL),
+  m_prepared_config(NULL),
+  m_node_id(0),
+  m_datadir(NULL)
+{
+}
+
+
+ConfigManager::~ConfigManager()
+{
+  delete m_config;
+  delete m_new_config;
+  delete m_prepared_config;
+  NdbMutex_Destroy(m_config_mutex);
+}
+
+
+
+bool
+ConfigManager::init_nodeid(void)
+{
+  DBUG_ENTER("ConfigManager::init_nodeid");
+
+  NodeId nodeid= m_config_retriever.get_configuration_nodeid();
+  DBUG_PRINT("info", ("nodeid: %d", nodeid));
+
+  if (nodeid)
+  {
+    // Nodeid was specifed on command line or in NDB_CONNECTSTRING
+    m_node_id= nodeid;
+    DBUG_RETURN(true);
+  }
+
+#if 0
+  // We _could_ try connecting to other running mgmd(s)
+  // and fetch our nodeid. But, that introduces a dependency
+  // that is not beneficial for a shared nothing cluster, since
+  // it might only work when other mgmd(s) are started. If all
+  // mgmd(s) is down it would require manual intervention.
+  // Better to require the node id to always be specified
+  // on the command line(or some other "local" magic by
+  // examining --datadir)
+
+  // Try to alloc nodeid from other mgmd
+  char buf[128];
+  g_eventLogger->info("Trying to get nodeid from other mgmd(s) "\
+                      "using '%s'...",
+                      m_config_retriever.get_connectstring(buf, sizeof(buf)));
+
+  if (m_config_retriever.do_connect(3, /* retry */
+                                    1, /* delay */
+                                    0  /* verbose */) == 0)
+  {
+    g_eventLogger->info("Connected...");
+
+    nodeid = m_config_retriever.allocNodeId(3, /* retry */
+                                            1  /* delay */);
+    if (nodeid == 0)
+    {
+      // Failed to alloc nodeid from other mgmd
+      g_eventLogger->error(m_config_retriever.getErrorString());
+      DBUG_RETURN(false);
+    }
+  }
+#endif
+
+  g_eventLogger->error("Could not determine which nodeid to use for "\
+                       "this node. Specify it with --ndb-nodeid=<nodeid> "\
+                       "on command line");
+  DBUG_RETURN(false);
+}
+
+
+bool
+ConfigManager::init(void)
+{
+  DBUG_ENTER("ConfigManager::init");
+
+  m_config_mutex = NdbMutex_Create();
+  if (!m_config_mutex)
+  {
+    g_eventLogger->error("Failed to create mutex in ConfigManager!");
+    DBUG_RETURN(false);
+  }
+
+  require(m_config_state == CS_UNINITIALIZED);
+
+  if (m_config_retriever.hasError())
+  {
+    g_eventLogger->error(m_config_retriever.getErrorString());
+    DBUG_RETURN(false);
+  }
+
+  // Check datadir
+  if (m_opts.datadir)
+  {
+    // Specified on commmand line
+    if (access(m_opts.datadir, F_OK))
+    {
+      g_eventLogger->error("Directory '%s' specified with --datadir "   \
+                           "does not exist", m_opts.datadir);
+      DBUG_RETURN(false);
+    }
+    m_datadir= m_opts.datadir;
+  }
+  else
+  {
+    // Compiled in path MYSQLCLUSTERDIR
+    if (access(MYSQLCLUSTERDIR, F_OK))
+    {
+      g_eventLogger->error("The default data directory '%s' "            \
+                           "does not exist. Either create it or "       \
+                           "specify a different directory with "        \
+                           "--datadir=<path>",
+                           MYSQLCLUSTERDIR);
+      DBUG_RETURN(false);
+    }
+    m_datadir= MYSQLCLUSTERDIR;
+  }
+  DBUG_PRINT("info", ("datadir: %s", m_datadir));
+
+  if (!init_nodeid())
+    DBUG_RETURN(false);
+
+  BaseString config_bin_name;
+  if (saved_config_exists(config_bin_name))
+  {
+    Config* conf = NULL;
+    if (!(conf = load_saved_config(config_bin_name)))
+      DBUG_RETURN(false);
+
+    if (!config_ok(conf))
+      DBUG_RETURN(false);
+
+    set_config(conf);
+    m_config_state = CS_CONFIRMED;
+
+    if (m_opts.mycnf || m_opts.config_filename)
+    {
+      Config* new_conf = NULL;
+      if (m_opts.mycnf && (new_conf = load_init_mycnf()) == NULL)
+      {
+        g_eventLogger->error("Could not load configuration from 'my.cnf'");
+        DBUG_RETURN(false);
+      }
+      else if (m_opts.config_filename &&
+               (new_conf = load_init_config(m_opts.config_filename)) == NULL)
+      {
+        g_eventLogger->error("Could not load configuration from '%s'",
+                             m_opts.config_filename);
+        DBUG_RETURN(false);
+      }
+
+      /* Copy the necessary values from old to new config */
+      if (!new_conf->setGeneration(m_config->getGeneration()))
+      {
+        g_eventLogger->error("Failed to copy generation from old config");
+        DBUG_RETURN(false);
+      }
+
+      if (!new_conf->setName(m_config->getName()))
+      {
+        g_eventLogger->error("Failed to copy name from old config");
+        DBUG_RETURN(false);
+      }
+
+      /* Check if config has changed */
+      if (!m_config->equal(new_conf))
+      {
+        /* Loaded config is different */
+        BaseString buf;
+        g_eventLogger->info("Detected change of %s on disk, will try to " \
+                            "set it when all ndb_mgmd(s) started. "     \
+                            "This is the actual diff:\n%s",
+                            m_opts.mycnf ? "my.cnf" : m_opts.config_filename,
+                            m_config->diff2str(new_conf, buf));
+        m_new_config= new_conf;
+      }
+      else
+      {
+        /* Loaded config was equal to current */
+        g_eventLogger->info("Config equal!");
+        delete new_conf;
+      }
+    }
+  }
+  else
+  {
+    if (m_opts.mycnf || m_opts.config_filename)
+    {
+      Config* conf = NULL;
+      if (m_opts.mycnf && (conf = load_init_mycnf()) == NULL)
+      {
+        g_eventLogger->error("Could not load configuration from 'my.cnf'");
+        DBUG_RETURN(false);
+      }
+      else if (m_opts.config_filename &&
+               (conf = load_init_config(m_opts.config_filename)) == NULL)
+      {
+        g_eventLogger->error("Could not load initial configuration from '%s'",
+                             m_opts.config_filename);
+        DBUG_RETURN(false);
+      }
+
+      if (!config_ok(conf))
+        DBUG_RETURN(false);
+
+      /* Use the initial config for now */
+      set_config(conf);
+
+      g_eventLogger->info("Got initial configuration from '%s', will try " \
+                          "to set it when all ndb_mgmd(s) started",
+                          m_opts.mycnf ? "my.cnf" : m_opts.config_filename);
+      m_new_config = new Config(conf); // Copy config
+      m_config_state = CS_INITIAL;
+    }
+    else
+    {
+      Config* conf = NULL;
+      if (!(conf = fetch_config()))
+      {
+        g_eventLogger->error("Could not fetch config!");
+        DBUG_RETURN(false);
+      }
+
+      if (!config_ok(conf))
+        DBUG_RETURN(false);
+
+      /* Use the fetched config for now */
+      set_config(conf);
+      m_new_config = new Config(conf); // Copy config
+
+      if (m_config->getGeneration() == 0)
+      {
+        g_eventLogger->info("Fetched initial configuration, " \
+                            "generation: %d, name: '%s'. "\
+                            "Will try to set it when all ndb_mgmd(s) started",
+                            m_config->getGeneration(), m_config->getName());
+        m_config_state= CS_INITIAL;
+      }
+      else
+      {
+        g_eventLogger->info("Fetched confirmed configuration, " \
+                            "generation: %d, name: '%s'. " \
+                            "Trying to write it to disk...",
+                            m_config->getGeneration(), m_config->getName());
+        if (!prepareConfigChange(m_config))
+        {
+          abortConfigChange();
+          g_eventLogger->error("Failed to write the fetched config to disk");
+          DBUG_RETURN(false);
+        }
+        commitConfigChange();
+        m_config_state = CS_CONFIRMED;
+        g_eventLogger->info("The fetched configuration has been saved!");
+      }
+    }
+  }
+
+  require(m_config_state != CS_UNINITIALIZED);
+  DBUG_RETURN(true);
+}
+
+
+bool
+ConfigManager::prepareConfigChange(const Config* config)
+{
+  if (m_prepared_config)
+  {
+    g_eventLogger->error("Can't prepare configuration change " \
+                         "when already prepared");
+    return false;
+  }
+  Uint32 generation= config->getGeneration();
+  if (generation == 0)
+  {
+    g_eventLogger->error("Can't prepare configuration change for "\
+                         "configuration with generation 0");
+    return false;
+  }
+
+  assert(m_node_id);
+  m_config_name.assfmt("%s/ndb_%u_config.bin.%u",
+                       m_datadir, m_node_id, generation);
+  g_eventLogger->debug("Preparing configuration, generation: %d name: %s",
+                      m_config_name.c_str());
+
+  /* Check file name is free */
+  if (access(m_config_name.c_str(), F_OK) == 0)
+  {
+    g_eventLogger->error("The file '%s' already exist while preparing",
+                         m_config_name.c_str());
+    return false;
+  }
+
+  /* Pack the config */
+  UtilBuffer buf;
+  if(!config->pack(buf))
+  {
+    /* Failed to pack config */
+    g_eventLogger->error("Failed to pack configuration while preparing");
+    return false;
+  }
+
+  /* Write config to temporary file */
+  BaseString prep_config_name(m_config_name);
+  prep_config_name.append(".tmp");
+  FILE * f = fopen(prep_config_name.c_str(), IF_WIN("wbc", "w"));
+  if(f == NULL)
+  {
+    g_eventLogger->error("Failed to open file '%s' while preparing, errno: %d",
+                         prep_config_name.c_str(), errno);
+    return false;
+  }
+
+  if(fwrite(buf.get_data(), 1, buf.length(), f) != (size_t)buf.length())
+  {
+    g_eventLogger->error("Failed to write file '%s' while preparing, errno: %d",
+                         prep_config_name.c_str(), errno);
+    fclose(f);
+    unlink(prep_config_name.c_str());
+    return false;
+  }
+
+  if (fflush(f))
+  {
+    g_eventLogger->error("Failed to flush file '%s' while preparing, errno: %d",
+                         prep_config_name.c_str(), errno);
+    fclose(f);
+    unlink(prep_config_name.c_str());
+    return false;
+  }
+
+#ifdef __WIN__
+  /* 
+	File is opened with the commit flag "c" so
+	that the contents of the file buffer are written
+	directly to disk when fflush is called
+  */
+#else
+  if (fsync(fileno(f)))
+  {
+    g_eventLogger->error("Failed to sync file '%s' while preparing, errno: %d",
+                         prep_config_name.c_str(), errno);
+    fclose(f);
+    unlink(prep_config_name.c_str());
+    return false;
+  }
+#endif
+  fclose(f);
+
+  m_prepared_config = new Config(config->m_configValues);
+  g_eventLogger->debug("Configuration prepared");
+
+  return true;
+}
+
+
+void
+ConfigManager::commitConfigChange(void)
+{
+  require(m_prepared_config);
+
+  /* Set new config locally and in all subscribers */
+  set_config(m_prepared_config);
+  m_prepared_config= NULL;
+
+  /* Rename file to real name */
+  require(m_config_name.length());
+  BaseString prep_config_name(m_config_name);
+  prep_config_name.append(".tmp");
+  if(rename(prep_config_name.c_str(), m_config_name.c_str()))
+  {
+    g_eventLogger->error("rename from '%s' to '%s' failed while committing, " \
+                         "errno: %d",
+                         prep_config_name.c_str(), m_config_name.c_str(),
+                         errno);
+    // Crash and leave the prepared config file in place
+    abort();
+  }
+  m_config_name.clear();
+
+  g_eventLogger->info("Configuration %d commited", m_config->getGeneration());
+}
+
+
+void
+ConfigManager::set_config(Config* new_config)
+{
+  delete m_config;
+  m_config = new_config;
+
+  for (unsigned i = 0; i < m_subscribers.size(); i++)
+    m_subscribers[i]->config_changed(m_node_id, new_config);
+
+}
+
+
+int
+ConfigManager::add_config_change_subscriber(ConfigSubscriber* subscriber)
+{
+  return m_subscribers.push_back(subscriber);
+}
+
+
+bool
+ConfigManager::config_ok(const Config* conf)
+{
+  assert(m_node_id);
+  if (!m_config_retriever.verifyConfig(conf->m_configValues, m_node_id))
+  {
+    g_eventLogger->error(m_config_retriever.getErrorString());
+    return false;
+  }
+
+  // Check if --datadir is same as DataDir from config
+  assert(m_datadir);
+  ConfigIter iter(conf, CFG_SECTION_NODE);
+  require(iter.find(CFG_NODE_ID, m_node_id) == 0);
+
+  const char *datadir;
+  require(iter.get(CFG_NODE_DATADIR, &datadir) == 0);
+
+  if (strcmp(datadir, "") != 0 &&        // Not set -> empty string
+      strcmp(m_datadir, datadir) != 0)   // Different
+  {
+    // Not same --datadir and DataDir
+    if (strcmp(m_datadir, MYSQLCLUSTERDIR) == 0 ||
+        strcmp(datadir, MYSQLCLUSTERDIR) == 0)
+    {
+      // Using the builtin default --datadir
+      g_eventLogger->error("The builtin data directory '%s' does "      \
+                           "not match DataDir=%s specified in "         \
+                           "configuation. Either specify --datadir=%s " \
+                           "on command line or remove the DataDir=%s "  \
+                           "from configuration in order to use the "    \
+                           "builtin default.",
+                           m_datadir, datadir, m_datadir, datadir);
+      return false;
+    }
+    else
+    {
+      // Using --datadir specified on command line
+      g_eventLogger->error("The data directory specified on command line " \
+                           "with --datadir=%s does not match DataDir=%s " \
+                           "specified in configuration. You need to "    \
+                           "change one of them.",
+                           m_datadir, datadir);
+      return false;
+    }
+  }
+  NdbConfig_SetPath(m_datadir);
+
+  return true;
+}
+
+
+void
+ConfigManager::abortConfigChange(void)
+{
+  /* Should always succeed */
+
+  /* Remove the prepared file */
+  BaseString prep_config_name(m_config_name);
+  prep_config_name.append(".tmp");
+  unlink(prep_config_name.c_str());
+  m_config_name.clear();
+
+  delete m_prepared_config;
+  m_prepared_config= NULL;
+}
+
+
+
+void
+ConfigManager::sendConfigChangeImplRef(SignalSender& ss, NodeId nodeId,
+                                       ConfigChangeRef::ErrorCode error) const
+{
+  SimpleSignal ssig;
+  ConfigChangeImplRef* const ref =
+    CAST_PTR(ConfigChangeImplRef, ssig.getDataPtrSend());
+  ref->errorCode = error;
+
+  g_eventLogger->debug("Send CONFIG_CHANGE_IMPL_REF to node: %d, error: %d",
+                       nodeId, error);
+
+  ss.sendSignal(nodeId, ssig,
+                MGM_CONFIG_MAN, GSN_CONFIG_CHANGE_IMPL_REF,
+                ConfigChangeImplRef::SignalLength);
+}
+
+
+
+void
+ConfigManager::execCONFIG_CHANGE_IMPL_REQ(SignalSender& ss, SimpleSignal* sig)
+{
+  NodeId nodeId = refToNode(sig->header.theSendersBlockRef);
+  const ConfigChangeImplReq * const req =
+    CAST_CONSTPTR(ConfigChangeImplReq, sig->getDataPtr());
+
+  g_eventLogger->debug("Got CONFIG_CHANGE_IMPL_REQ from node: %d, "\
+                       "requestType: %d",
+                       nodeId, req->requestType);
+
+  Guard g(m_config_mutex);
+
+  switch(req->requestType){
+  case ConfigChangeImplReq::Prepare:{
+    if (sig->header.m_noOfSections != 1)
+    {
+      sendConfigChangeImplRef(ss, nodeId, ConfigChangeRef::NoConfigData);
+      return;
+    }
+
+    ConfigValuesFactory cf;
+    if (!cf.unpack(sig->ptr[0].p, req->length))
+    {
+      sendConfigChangeImplRef(ss, nodeId, ConfigChangeRef::FailedToUnpack);
+      return;
+    }
+
+    Config* new_config = new Config(cf.getConfigValues());
+    Uint32 new_generation = new_config->getGeneration();
+    Uint32 curr_generation = m_config->getGeneration();
+    const char* new_name = new_config->getName();
+    const char* curr_name = m_config->getName();
+
+    if (m_config->illegal_change(new_config))
+    {
+      sendConfigChangeImplRef(ss, nodeId, ConfigChangeRef::IllegalConfigChange);
+      return;
+    }
+
+    if (req->initial)
+    {
+      // Check own state
+      if (m_config_state != CS_INITIAL)
+      {
+        g_eventLogger->warning("Refusing to start initial "             \
+                               "configuration change since this node "  \
+                               "is not in INITIAL state");
+        sendConfigChangeImplRef(ss, nodeId, ConfigChangeRef::IllegalState);
+        return;
+      }
+
+      // Check generation
+      if (new_generation != 0)
+      {
+        g_eventLogger->warning("Refusing to start initial "             \
+                               "configuration change since new "        \
+                               "generation is not 0 (new_generation: %d)",
+                               new_generation);
+        sendConfigChangeImplRef(ss, nodeId,
+                                ConfigChangeRef::IllegalInitialGeneration);
+        return;
+      }
+      new_generation = 1;
+
+      // Check config is equal to our initial config
+      {
+        Config new_config_copy(new_config);
+        require(new_config_copy.setName(new_name));
+        unsigned exclude[]= {CFG_SECTION_SYSTEM, 0};
+        if (!new_config_copy.equal(m_new_config, exclude))
+        {
+          BaseString buf;
+          g_eventLogger->warning("Refusing to start initial config "    \
+                                 "change when nodes have different "    \
+                                 "config\n"                             \
+                                 "This is the actual diff:\n%s",
+                                 new_config_copy.diff2str(m_new_config, buf));
+          sendConfigChangeImplRef(ss, nodeId,
+                                  ConfigChangeRef::DifferentInitial);
+          return;
+        }
+      }
+
+      /*
+         Scrap the m_new_config, it's been used to check that other node
+         started from equal initial config, now it's not needed anymore
+      */
+      delete m_new_config;
+      m_new_config = NULL;
+
+    }
+    else
+    {
+      if (new_generation == 0 ||
+          new_generation != curr_generation)
+      {
+        BaseString buf;
+        g_eventLogger->warning("Refusing to start config change "     \
+                               "requested by node with different "    \
+                               "generation: %d. Our generation: %d\n" \
+                               "This is the actual diff:\n%s",
+                               new_generation, curr_generation,
+                               new_config->diff2str(m_config, buf));
+        sendConfigChangeImplRef(ss, nodeId, ConfigChangeRef::InvalidGeneration);
+        return;
+      }
+      new_generation++;
+
+      // Check same cluster name
+      if (strcmp(new_name, curr_name))
+      {
+        BaseString buf;
+        g_eventLogger->warning("Refusing to start config change "       \
+                               "requested by node with different "      \
+                               "name: '%s'. Our name: '%s'\n"           \
+                               "This is the actual diff:\n%s",
+                               new_name, curr_name,
+                               new_config->diff2str(m_config, buf));
+        sendConfigChangeImplRef(ss, nodeId, ConfigChangeRef::InvalidConfigName);
+        return;
+      }
+    }
+
+    // Set new generation
+    if(!new_config->setGeneration(new_generation))
+    {
+      g_eventLogger->error("Failed to set new generation to %d",
+                           new_generation);
+      sendConfigChangeImplRef(ss, nodeId, ConfigChangeRef::SetGenerationFailed);
+      return;
+    }
+
+    if (!prepareConfigChange(new_config))
+    {
+      sendConfigChangeImplRef(ss, nodeId, ConfigChangeRef::PrepareFailed);
+      return;
+    }
+    break;
+  }
+
+  case ConfigChangeImplReq::Commit:
+    commitConfigChange();
+
+    // All nodes has agreed on config -> CONFIRMED
+    m_config_state = CS_CONFIRMED;
+
+    break;
+
+  case ConfigChangeImplReq::Abort:
+    abortConfigChange();
+    break;
+
+  default:
+    g_eventLogger->error("execCONFIG_CHANGE_IMPL_REQ: unhandled state");
+    abort();
+    break;
+  }
+
+  /* Send CONF */
+  SimpleSignal ssig;
+  ConfigChangeImplConf* const conf =
+    CAST_PTR(ConfigChangeImplConf, ssig.getDataPtrSend());
+  conf->requestType = req->requestType;
+
+  g_eventLogger->debug("Sending CONFIG_CHANGE_IMPL_CONF to node: %d",
+                       nodeId);
+
+  ss.sendSignal(nodeId, ssig,
+                MGM_CONFIG_MAN,
+                GSN_CONFIG_CHANGE_IMPL_CONF,
+                ConfigChangeImplConf::SignalLength);
+}
+
+
+void
+ConfigManager::execCONFIG_CHANGE_IMPL_REF(SignalSender& ss, SimpleSignal* sig)
+{
+  NodeId nodeId = refToNode(sig->header.theSendersBlockRef);
+  g_eventLogger->debug("Got CONFIG_CHANGE_IMPL_REF from node: %d", nodeId);
+
+  const ConfigChangeImplRef * const ref =
+    CAST_CONSTPTR(ConfigChangeImplRef, sig->getDataPtr());
+  g_eventLogger->warning("Node %d refused configuration change, error: %d",
+                         nodeId, ref->errorCode);
+
+  switch(m_config_change_state){
+
+  case CCS_PREPARING:{
+    /* Got ref while preparing */
+    m_config_change_state = CCS_ABORT;
+    m_waiting_for.clear(nodeId);
+    if (!m_waiting_for.isclear())
+      return;
+
+    /* Abort all other nodes */
+    SimpleSignal ssig;
+    ConfigChangeImplReq* const req =
+      CAST_PTR(ConfigChangeImplReq, ssig.getDataPtrSend());
+    req->requestType = ConfigChangeImplReq::Abort;
+
+    g_eventLogger->debug("Sending CONFIG_CHANGE_IMPL_REQ(abort) to node %d",
+                         nodeId);
+    require(m_waiting_for.isclear());
+    m_waiting_for = ss.broadcastSignal(m_all_mgm, ssig,
+                                  MGM_CONFIG_MAN,
+                                  GSN_CONFIG_CHANGE_IMPL_REQ,
+                                  ConfigChangeImplReq::SignalLength);
+    if (m_waiting_for.isclear())
+      m_config_change_state = CCS_IDLE;
+    else
+      m_config_change_state = CCS_ABORTING;
+    break;
+  }
+
+  case CCS_COMITTING:
+    /* Got ref while comitting, impossible */
+    abort();
+    break;
+
+  case CCS_ABORT:{
+    /* Got ref(another) while already decided to abort */
+    m_waiting_for.clear(nodeId);
+    if (!m_waiting_for.isclear())
+      return;
+
+    /* Abort all other nodes */
+    SimpleSignal ssig;
+    ConfigChangeImplReq* const req =
+      CAST_PTR(ConfigChangeImplReq, ssig.getDataPtrSend());
+    req->requestType = ConfigChangeImplReq::Abort;
+
+    g_eventLogger->debug("Sending CONFIG_CHANGE_IMPL_REQ(abort) to node %d",
+                         nodeId);
+    require(m_waiting_for.isclear());
+    m_waiting_for = ss.broadcastSignal(m_all_mgm, ssig,
+                                  MGM_CONFIG_MAN,
+                                  GSN_CONFIG_CHANGE_IMPL_REQ,
+                                  ConfigChangeImplReq::SignalLength);
+    if (m_waiting_for.isclear())
+      m_config_change_state = CCS_IDLE;
+    else
+      m_config_change_state = CCS_ABORTING;
+    break;
+  }
+
+  case CCS_ABORTING:
+    /* Got ref while aborting, impossible */
+    abort();
+    break;
+
+  default:
+    g_eventLogger->error("execCONFIG_CHANGE_IMPL_REF: unhandled state");
+    abort();
+    break;
+  }
+}
+
+
+void
+ConfigManager::execCONFIG_CHANGE_IMPL_CONF(SignalSender& ss, SimpleSignal* sig)
+{
+  NodeId nodeId = refToNode(sig->header.theSendersBlockRef);
+  const ConfigChangeImplConf * const conf =
+    CAST_CONSTPTR(ConfigChangeImplConf, sig->getDataPtr());
+  g_eventLogger->debug("Got CONFIG_CHANGE_IMPL_CONF from node %d", nodeId);
+
+  switch(m_config_change_state){
+  case CCS_PREPARING:{
+    require(conf->requestType == ConfigChangeImplReq::Prepare);
+    m_waiting_for.clear(nodeId);
+    if (!m_waiting_for.isclear())
+      return;
+
+    /* Send commit to all nodes */
+    SimpleSignal ssig;
+    ConfigChangeImplReq* const req =
+      CAST_PTR(ConfigChangeImplReq, ssig.getDataPtrSend());
+
+    req->requestType = ConfigChangeImplReq::Commit;
+
+    g_eventLogger->debug("Sending CONFIG_CHANGE_IMPL_REQ(commit)");
+    require(m_waiting_for.isclear());
+    m_waiting_for = ss.broadcastSignal(m_all_mgm, ssig,
+                                  MGM_CONFIG_MAN,
+                                  GSN_CONFIG_CHANGE_IMPL_REQ,
+                                  ConfigChangeImplReq::SignalLength);
+    if (m_waiting_for.isclear())
+      m_config_change_state = CCS_IDLE;
+    else
+      m_config_change_state = CCS_COMITTING;
+    break;
+  }
+
+  case CCS_COMITTING:{
+    require(conf->requestType == ConfigChangeImplReq::Commit);
+
+    m_waiting_for.clear(nodeId);
+    if (!m_waiting_for.isclear())
+      return;
+
+    require(m_client_ref != RNIL);
+    if (m_client_ref == ss.getOwnRef())
+    {
+      g_eventLogger->info("Config change completed! New generation: %d",
+                          m_config->getGeneration());
+    }
+    else
+    {
+      /* Send CONF to requestor */
+      sendConfigChangeConf(ss, m_client_ref);
+    }
+    m_client_ref = RNIL;
+    m_config_change_state = CCS_IDLE;
+    break;
+  }
+
+  case CCS_ABORT:{
+    m_waiting_for.clear(nodeId);
+    if (!m_waiting_for.isclear())
+      return;
+
+    /* Abort all other nodes */
+    SimpleSignal ssig;
+    ConfigChangeImplReq* const req =
+      CAST_PTR(ConfigChangeImplReq, ssig.getDataPtrSend());
+    req->requestType = ConfigChangeImplReq::Abort;
+
+    g_eventLogger->debug("Sending CONFIG_CHANGE_IMPL_REQ(abort)");
+    require(m_waiting_for.isclear());
+    m_waiting_for = ss.broadcastSignal(m_all_mgm, ssig,
+                                  MGM_CONFIG_MAN,
+                                  GSN_CONFIG_CHANGE_IMPL_REQ,
+                                  ConfigChangeImplReq::SignalLength);
+    if (m_waiting_for.isclear())
+        m_config_change_state = CCS_IDLE;
+    else
+      m_config_change_state = CCS_ABORTING;
+    break;
+  }
+
+  case CCS_ABORTING:{
+    m_waiting_for.clear(nodeId);
+    if (!m_waiting_for.isclear())
+      return;
+
+    require(m_client_ref != RNIL);
+    if (m_client_ref == ss.getOwnRef())
+    {
+      g_eventLogger->error("Config change failed!");
+      exit(1);
+    }
+    else
+    {
+      /* Send ref to the requestor */
+      sendConfigChangeRef(ss, m_client_ref,
+                          ConfigChangeRef::ConfigChangeAborted);
+    }
+    m_client_ref = RNIL;
+    m_config_change_state = CCS_IDLE;
+    break;
+  }
+
+  default:
+    g_eventLogger->error("execCONFIG_CHANGE_IMPL_CONF: unhandled state");
+    abort();
+    break;
+  }
+}
+
+
+void
+ConfigManager::sendConfigChangeRef(SignalSender& ss, BlockReference to,
+                                   ConfigChangeRef::ErrorCode error) const
+{
+  NodeId nodeId = refToNode(to);
+  SimpleSignal ssig;
+  ConfigChangeRef* const ref =
+    CAST_PTR(ConfigChangeRef, ssig.getDataPtrSend());
+  ref->errorCode = error;
+
+  g_eventLogger->debug("Send CONFIG_CHANGE_REF to node: %d, error: %d",
+                       nodeId, error);
+
+  ss.sendSignal(nodeId, ssig, refToBlock(to),
+                GSN_CONFIG_CHANGE_REF, ConfigChangeRef::SignalLength);
+}
+
+
+void
+ConfigManager::sendConfigChangeConf(SignalSender& ss, BlockReference to) const
+{
+  NodeId nodeId = refToNode(to);
+  SimpleSignal ssig;
+
+  g_eventLogger->debug("Send CONFIG_CHANGE_CONF to node: %d", nodeId);
+
+  ss.sendSignal(nodeId, ssig, refToBlock(to),
+                GSN_CONFIG_CHANGE_CONF, ConfigChangeConf::SignalLength);
+}
+
+
+void
+ConfigManager::startInitConfigChange(SignalSender& ss)
+{
+  require(m_config_state == CS_INITIAL);
+  g_eventLogger->info("Starting initial configuration change");
+  m_client_ref = ss.getOwnRef();
+  sendConfigChangeImplReq(ss, m_new_config);
+}
+
+
+void
+ConfigManager::startNewConfigChange(SignalSender& ss)
+{
+  require(m_config_state == CS_CONFIRMED);
+  g_eventLogger->info("Starting configuration change, generation: %d",
+                      m_new_config->getGeneration());
+  m_client_ref = ss.getOwnRef();
+  sendConfigChangeImplReq(ss, m_new_config);
+
+  /* The new config has been sent and can now be discarded */
+  delete m_new_config;
+  m_new_config = NULL;
+}
+
+
+void
+ConfigManager::sendConfigChangeImplReq(SignalSender& ss, const Config* conf)
+{
+  require(m_client_ref != RNIL);
+
+  /* Send prepare to all MGM nodes */
+  SimpleSignal ssig;
+
+  UtilBuffer buf;
+  conf->pack(buf);
+  ssig.ptr[0].p = (Uint32*)buf.get_data();
+  ssig.ptr[0].sz = (buf.length() + 3) / 4;
+  ssig.header.m_noOfSections = 1;
+
+  ConfigChangeImplReq* const req =
+    CAST_PTR(ConfigChangeImplReq, ssig.getDataPtrSend());
+  req->requestType = ConfigChangeImplReq::Prepare;
+  req->initial = (m_config_state == CS_INITIAL);
+  req->length = buf.length();
+
+  g_eventLogger->debug("Sending CONFIG_CHANGE_IMPL_REQ(prepare)");
+
+  require(m_waiting_for.isclear());
+  m_waiting_for = ss.broadcastSignal(m_all_mgm, ssig,
+                                MGM_CONFIG_MAN,
+                                GSN_CONFIG_CHANGE_IMPL_REQ,
+                                ConfigChangeImplReq::SignalLength);
+  if (!m_waiting_for.isclear())
+    m_config_change_state = CCS_ABORT;
+  else
+    require(m_config_change_state == CCS_IDLE);
+  m_config_change_state = CCS_PREPARING;
+}
+
+
+void
+ConfigManager::execCONFIG_CHANGE_REQ(SignalSender& ss, SimpleSignal* sig)
+{
+  BlockReference from = sig->header.theSendersBlockRef;
+  const ConfigChangeReq * const req =
+    CAST_CONSTPTR(ConfigChangeReq, sig->getDataPtr());
+
+  if (!m_started.equal(m_all_mgm)) // Not all started
+  {
+    sendConfigChangeRef(ss, from, ConfigChangeRef::NotAllStarted);
+    return;
+  }
+
+  if (m_all_mgm.find(0) != m_facade->ownId()) // Not the master
+  {
+    sendConfigChangeRef(ss, from, ConfigChangeRef::NotMaster);
+    return;
+  }
+
+  if (m_config_change_state != CCS_IDLE)
+  {
+    sendConfigChangeRef(ss, from, ConfigChangeRef::ConfigChangeOnGoing);
+    return;
+  }
+
+  if (sig->header.m_noOfSections != 1)
+  {
+    sendConfigChangeRef(ss, from, ConfigChangeRef::NoConfigData);
+    return;
+  }
+
+  ConfigValuesFactory cf;
+  if (!cf.unpack(sig->ptr[0].p, req->length))
+  {
+    sendConfigChangeRef(ss, from, ConfigChangeRef::FailedToUnpack);
+    return;
+  }
+
+  Config new_config(cf.getConfigValues());
+  if (!config_ok(&new_config))
+  {
+    g_eventLogger->warning("Refusing to start config change, the config "\
+                           "is not ok");
+    sendConfigChangeRef(ss, from, ConfigChangeRef::FailedToUnpack);
+    return;
+  }
+
+  m_client_ref = from;
+  sendConfigChangeImplReq(ss, &new_config);
+  return;
+}
+
+
+void
+ConfigManager::execCONFIG_CHECK_REQ(SignalSender& ss, SimpleSignal* sig)
+{
+  Guard g(m_config_mutex);
+  BlockReference from = sig->header.theSendersBlockRef;
+  NodeId nodeId = refToNode(from);
+  const ConfigCheckReq * const req =
+    CAST_CONSTPTR(ConfigCheckReq, sig->getDataPtr());
+
+  Uint32 other_generation = req->generation;
+  ConfigState other_state = (ConfigState)req->state;
+
+  Uint32 generation = m_config->getGeneration();
+
+  g_eventLogger->debug("Got CONFIG_CHECK_REQ from node: %d. "   \
+                       "generation: %d, other_generation: %d, " \
+                       "our state: %d, other state: %d",
+                       generation, other_generation,
+                       m_config_state, other_state, nodeId);
+
+  switch (m_config_state)
+  {
+  default:
+  case CS_UNINITIALIZED:
+    g_eventLogger->error("execCONFIG_CHECK_REQ: unhandled state");
+    abort();
+    break;
+
+  case CS_INITIAL:
+    if (other_state != CS_INITIAL)
+    {
+      g_eventLogger->error("Other node are not in INITIAL");
+      exit(1);
+    }
+
+    require(generation == 0);
+    if (other_generation != generation)
+    {
+      g_eventLogger->warning("Refusing other node, it has different "   \
+                             "generation: %d, expected: %d",
+                             other_generation, generation);
+      sendConfigCheckRef(ss, from, ConfigCheckRef::WrongGeneration,
+                         generation, other_generation,
+                         m_config_state, other_state);
+      return;
+    }
+    break;
+
+  case CS_CONFIRMED:
+    if (other_state != CS_CONFIRMED)
+    {
+      g_eventLogger->warning("Refusing other node, it's in different "  \
+                             "state: %d, expected: %d",
+                             other_state, m_config_state);
+      sendConfigCheckRef(ss, from, ConfigCheckRef::WrongState,
+                         generation, other_generation,
+                         m_config_state, other_state);
+      return;
+    }
+
+    if (other_generation == generation)
+    {
+      ;// OK
+    }
+    else if (other_generation < generation)
+    {
+      g_eventLogger->warning("Refusing other node, it has lower "       \
+                             " generation: %d, expected: %d",
+                             other_generation, generation);
+      sendConfigCheckRef(ss, from, ConfigCheckRef::WrongGeneration,
+                         generation, other_generation,
+                         m_config_state, other_state);
+      return;
+    }
+    else
+    {
+      g_eventLogger->error("Other node has higher generation: %d, this " \
+                           "node is out of sync with generation: %d",
+                           other_generation, generation);
+      exit(1);
+    }
+
+    break;
+  }
+
+  sendConfigCheckConf(ss, from);
+  return;
+}
+
+
+void
+ConfigManager::sendConfigCheckReq(SignalSender& ss, NodeBitmask to)
+{
+  SimpleSignal ssig;
+  ConfigCheckReq* const req =
+    CAST_PTR(ConfigCheckReq, ssig.getDataPtrSend());
+  req->state =        m_config_state;
+  req->generation =   m_config->getGeneration();
+
+  BaseString buf("Sending CONFIG_CHECK_REQ to node(s) ");
+  unsigned i = 0;
+  while((i = to.find(i+1)) != NodeBitmask::NotFound)
+    buf.appfmt("%d ", i);
+  g_eventLogger->debug(buf);
+
+  require(m_waiting_for.isclear());
+  m_waiting_for = ss.broadcastSignal(to, ssig, MGM_CONFIG_MAN,
+                                GSN_CONFIG_CHECK_REQ,
+                                ConfigCheckReq::SignalLength);
+}
+
+
+void
+ConfigManager::sendConfigCheckRef(SignalSender& ss, BlockReference to,
+                                  ConfigCheckRef::ErrorCode error,
+                                  Uint32 generation,
+                                  Uint32 other_generation,
+                                  ConfigState state,
+                                  ConfigState other_state) const
+{
+  NodeId nodeId = refToNode(to);
+  SimpleSignal ssig;
+  ConfigCheckRef* const ref =
+    CAST_PTR(ConfigCheckRef, ssig.getDataPtrSend());
+  ref->error = error;
+  ref->generation = other_generation;
+  ref->expected_generation = generation;
+  ref->state = other_state;
+  ref->expected_state = state;
+
+  g_eventLogger->debug("Send CONFIG_CHECK_REF with error: %d to node: %d",
+                       error, nodeId);
+
+  ss.sendSignal(nodeId, ssig, MGM_CONFIG_MAN,
+                GSN_CONFIG_CHECK_REF, ConfigCheckReq::SignalLength);
+}
+
+
+void
+ConfigManager::sendConfigCheckConf(SignalSender& ss, BlockReference to) const
+{
+  NodeId nodeId = refToNode(to);
+  SimpleSignal ssig;
+  ConfigCheckConf* const conf =
+    CAST_PTR(ConfigCheckConf, ssig.getDataPtrSend());
+  conf->state = m_config_state;
+  conf->generation = m_config->getGeneration();
+
+  g_eventLogger->debug("Send CONFIG_CHECK_CONF to node: %d", nodeId);
+
+  ss.sendSignal(nodeId, ssig, MGM_CONFIG_MAN,
+                GSN_CONFIG_CHECK_CONF, ConfigCheckReq::SignalLength);
+}
+
+
+void
+ConfigManager::execCONFIG_CHECK_CONF(SignalSender& ss, SimpleSignal* sig)
+{
+  BlockReference from = sig->header.theSendersBlockRef;
+  NodeId nodeId = refToNode(from);
+  m_waiting_for.clear(nodeId);
+  m_checked.set(nodeId);
+
+  g_eventLogger->debug("Got CONFIG_CHECK_CONF from node: %d",
+                       nodeId);
+
+  return;
+}
+
+
+void
+ConfigManager::execCONFIG_CHECK_REF(SignalSender& ss, SimpleSignal* sig)
+{
+  BlockReference from = sig->header.theSendersBlockRef;
+  NodeId nodeId = refToNode(from);
+
+  const ConfigCheckRef* const ref =
+    CAST_CONSTPTR(ConfigCheckRef, sig->getDataPtr());
+
+  g_eventLogger->error("Got CONFIG_CHECK_REF from node %d, "   \
+                       "error: %d, message: '%s'\n"            \
+                       "generation: %d, expected generation: %d\n"\
+                       "state: %d, expected state: %d",
+                       nodeId, ref->error,
+                       ConfigCheckRef::errorMessage(ref->error),
+                       ref->generation, ref->expected_generation,
+                       ref->state, ref->expected_state);
+  exit(1);
+}
+
+
+void
+ConfigManager::run()
+{
+  assert(m_facade);
+  SignalSender ss(m_facade, MGM_CONFIG_MAN);
+  ss.lock();
+
+  ss.getNodes(m_all_mgm, NodeInfo::MGM);
+
+  m_started.set(m_facade->ownId());
+
+  while (!is_stopped())
+  {
+
+    if (m_config_change_state == CCS_IDLE)
+    {
+      bool print_state = false;
+      if (m_previous_state != m_config_state)
+      {
+        print_state = true;
+        m_previous_state = m_config_state;
+      }
+
+      /*
+        Check if it's necessary to start something to get
+        out of the current state
+      */
+      switch (m_config_state){
+
+      case CS_UNINITIALIZED:
+        abort();
+        break;
+
+      case CS_INITIAL:
+        /*
+          INITIAL => CONFIRMED
+          When all mgm nodes has been started and checked that they
+          are also in INITIAL, the node with the lowest node id
+          will start an initial config change. When completed
+          all nodes will be in CONFIRMED
+        */
+
+        if (print_state)
+          ndbout_c("==INITIAL==");
+
+        if (m_new_config &&                     // Updated config.ini was found
+            m_started.equal(m_all_mgm) &&       // All mgmd started
+            m_checked.equal(m_started) &&       // All nodes checked
+            m_all_mgm.find(0) == m_facade->ownId()) // Lowest nodeid
+        {
+            startInitConfigChange(ss);
+        }
+        break;
+
+      case CS_CONFIRMED:
+        if (print_state)
+          ndbout_c("==CONFIRMED==");
+
+        if (m_new_config &&                 // Updated config.ini was found
+            m_started.equal(m_all_mgm) &&   // All mgmd started
+            m_checked.equal(m_started))     // All nodes checked
+        {
+          startNewConfigChange(ss);
+        }
+
+        break;
+
+      default:
+        break;
+      }
+
+      // Send CHECK_CONFIG to all nodes not yet checked
+      if (m_waiting_for.isclear() &&    // Nothing else ongoing
+          !m_checked.equal(m_started))  // Some nodes have not been checked
+      {
+        NodeBitmask not_checked;
+        not_checked.assign(m_started);
+        not_checked.bitANDC(m_checked);
+        sendConfigCheckReq(ss, not_checked);
+      }
+    }
+
+
+    SimpleSignal *sig = ss.waitFor((Uint32)1000);
+    if (!sig)
+      continue;
+
+    switch (sig->readSignalNumber()) {
+
+    case GSN_CONFIG_CHANGE_REQ:
+      execCONFIG_CHANGE_REQ(ss, sig);
+      break;
+
+    case GSN_CONFIG_CHANGE_IMPL_REQ:
+      execCONFIG_CHANGE_IMPL_REQ(ss, sig);
+      break;
+
+    case GSN_CONFIG_CHANGE_IMPL_REF:
+      execCONFIG_CHANGE_IMPL_REF(ss, sig);
+      break;
+
+    case GSN_CONFIG_CHANGE_IMPL_CONF:
+      execCONFIG_CHANGE_IMPL_CONF(ss, sig);
+      break;
+
+    case GSN_NF_COMPLETEREP:{
+      const NFCompleteRep * const rep =
+        CAST_CONSTPTR(NFCompleteRep, sig->getDataPtr());
+      NodeId nodeId= rep->failedNodeId;
+
+      if (m_all_mgm.get(nodeId)) // Not mgm node
+        break;
+
+      ndbout_c("Node %d failed", nodeId);
+      m_started.clear(nodeId);
+      m_checked.clear(nodeId);
+
+      if (m_config_change_state != CCS_IDLE)
+      {
+        g_eventLogger->info("Node %d failed during config change!!",
+                            nodeId);
+        // TODO start take over of config change protocol
+      }
+      break;
+    }
+
+    case GSN_NODE_FAILREP:
+      // ignore, NF_COMPLETEREP will come
+      break;
+
+    case GSN_API_REGCONF:{
+      NodeId nodeId = refToNode(sig->header.theSendersBlockRef);
+      if (m_all_mgm.get(nodeId) &&      // Is a mgm node
+          !m_started.get(nodeId))       // Not already marked as started
+      {
+        g_eventLogger->info("Node %d connected", nodeId);
+        m_started.set(nodeId);
+      }
+      break;
+    }
+
+    case GSN_CONFIG_CHECK_REQ:
+      execCONFIG_CHECK_REQ(ss, sig);
+      break;
+
+    case GSN_CONFIG_CHECK_REF:
+      execCONFIG_CHECK_REF(ss, sig);
+      break;
+
+    case GSN_CONFIG_CHECK_CONF:
+      execCONFIG_CHECK_CONF(ss, sig);
+      break;
+
+    default:
+      sig->print();
+      g_eventLogger->error("Unknown signal received. SignalNumber: "
+                           "%i from (%d, 0x%x)",
+                           sig->readSignalNumber(),
+                           refToNode(sig->header.theSendersBlockRef),
+                           refToBlock(sig->header.theSendersBlockRef));
+      abort();
+      break;
+    }
+  }
+}
+
+
+#include "InitConfigFileParser.hpp"
+
+Config*
+ConfigManager::load_init_config(const char* config_filename)
+{
+   InitConfigFileParser parser;
+   g_eventLogger->info("Reading cluster configuration from '%s'",
+                       config_filename);
+  return parser.parseConfig(config_filename);
+}
+
+
+Config*
+ConfigManager::load_init_mycnf(void)
+{
+  InitConfigFileParser parser;
+  g_eventLogger->info("Reading cluster configuration using my.cnf");
+  return parser.parse_mycnf();
+}
+
+
+Config*
+ConfigManager::fetch_config(void)
+{
+  DBUG_ENTER("ConfigManager::fetch_config");
+
+  /* Loop until config loaded from other mgmd(s) */
+  char buf[128];
+  g_eventLogger->info("Trying to get configuration from other mgmd(s) "\
+                      "using '%s'...",
+                      m_config_retriever.get_connectstring(buf, sizeof(buf)));
+
+  if (!m_config_retriever.is_connected())
+  {
+
+    if (m_config_retriever.do_connect(-1 /* retry */,
+                                      1 /* delay */,
+                                      0 /* verbose */) != 0)
+    {
+      g_eventLogger->error("INTERNAL ERROR: Inifinite wait for connect " \
+                           "returned!");
+      abort();
+    }
+    g_eventLogger->info("Connected...");
+
+  }
+
+  // read config from other management server
+  ndb_mgm_configuration * tmp =
+    m_config_retriever.getConfig(m_config_retriever.get_mgmHandle());
+  if (tmp == NULL) {
+    g_eventLogger->error(m_config_retriever.getErrorString());
+    DBUG_RETURN(false);
+  }
+
+  DBUG_RETURN(new Config(tmp));
+}
+
+
+#include "DirIterator.hpp"
+
+bool
+ConfigManager::saved_config_exists(BaseString& config_name) const
+{
+  DirIterator iter;
+
+  if (iter.open(m_datadir) != 0)
+    return false;
+
+  const char* name;
+  unsigned nodeid;
+  char extra; // Avoid matching ndb_2_config.bin.2.tmp
+  unsigned version, max_version= 0;
+  while ((name= iter.next_file()) != NULL)
+  {
+    if (sscanf(name,
+               "ndb_%u_config.bin.%u%c",
+               &nodeid, &version, &extra) == 2)
+    {
+      // ndbout_c("match: %s", name);
+
+      if (nodeid != m_node_id)
+        continue;
+
+      if (version>max_version)
+        max_version= version;
+    }
+  }
+
+  if (max_version == 0)
+    return false;
+
+  config_name.assfmt("%s%sndb_%u_config.bin.%u", 
+                     m_datadir, DIR_SEPARATOR, m_node_id, max_version);
+  return true;
+}
+
+
+Config*
+ConfigManager::load_saved_config(const BaseString& config_name)
+{
+  struct ndb_mgm_configuration * tmp =
+    m_config_retriever.getConfig(config_name.c_str());
+  if(tmp == NULL)
+  {
+    g_eventLogger->error("Failed to load config from '%s', error: '%s'",
+                         config_name.c_str(),
+                         m_config_retriever.getErrorString());
+    return NULL;
+  }
+
+  g_eventLogger->info("Loaded config from '%s'", config_name.c_str());
+  Config* conf = new Config(tmp);
+  if (conf == NULL)
+    g_eventLogger->error("Failed to load config, out of memory");
+  return conf;
+}
+
+
+bool
+ConfigManager::get_packed_config(UtilBuffer& pack_buf)
+{
+  Guard g(m_config_mutex);
+
+  /* Only allow the config to be exported if it's been confirmed */
+  if (m_config_state != CS_CONFIRMED)
+    return false;
+
+  require(m_config);
+  return m_config->pack(pack_buf);
+}
+
+
+template class Vector<ConfigSubscriber*>;
+

=== added file 'storage/ndb/src/mgmsrv/ConfigManager.hpp'
--- a/storage/ndb/src/mgmsrv/ConfigManager.hpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/mgmsrv/ConfigManager.hpp	2008-10-21 12:41:59 +0000
@@ -0,0 +1,153 @@
+/* Copyright (C) 2008 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef ConfigManager_H
+#define ConfigManager_H
+
+#include "MgmtThread.hpp"
+#include "Config.hpp"
+#include "ConfigSubscriber.hpp"
+#include "MgmtSrvr.hpp"
+
+#include <ConfigRetriever.hpp>
+
+#include <SignalSender.hpp>
+#include <NodeBitmask.hpp>
+
+#include <signaldata/ConfigChange.hpp>
+
+class ConfigManager : public MgmtThread {
+  const MgmtSrvr::MgmtOpts& m_opts;
+  TransporterFacade* m_facade;
+
+  NdbMutex *m_config_mutex;
+  const Config * m_config;
+  const Config * m_new_config;
+
+  ConfigRetriever m_config_retriever;
+
+  enum ConfigChangeState {
+    CCS_IDLE,
+    CCS_PREPARING,
+    CCS_COMITTING,
+    CCS_ABORT,
+    CCS_ABORTING
+  } m_config_change_state;
+
+  enum ConfigState {
+    CS_UNINITIALIZED,
+
+    CS_INITIAL,      // Initial config.ini, ie. no config.bin.X found
+
+    CS_CONFIRMED,    // Started and all agreed
+    CS_FORCED        // Forced start
+  };
+
+  ConfigState m_config_state;
+  ConfigState m_previous_state;
+
+  BlockReference m_client_ref;
+  BaseString m_config_name;
+  Config* m_prepared_config;
+
+  NodeBitmask m_all_mgm;
+  NodeBitmask m_started;
+  NodeBitmask m_waiting_for;
+  NodeBitmask m_checked;
+
+  NodeId m_node_id;
+
+  const char* m_datadir;
+
+  /* Functions used from 'init' */
+  Config* load_init_config(const char*);
+  Config* load_init_mycnf(void);
+  Config* fetch_config(void);
+  bool save_config(const Config* conf);
+  bool save_config(void);
+  bool saved_config_exists(BaseString& config_name) const;
+  Config* load_saved_config(const BaseString& config_name);
+  bool init_nodeid(void);
+
+  /* Set the new config and inform subscribers */
+  void set_config(Config* config);
+  Vector<ConfigSubscriber*> m_subscribers;
+
+  /* Check config is ok */
+  bool config_ok(const Config* conf);
+
+  /* Functions for writing config.bin to disk */
+  bool prepareConfigChange(const Config* config);
+  void commitConfigChange();
+  void abortConfigChange();
+
+  /* Functions for starting config change from ConfigManager */
+  void startInitConfigChange(SignalSender& ss);
+  void startNewConfigChange(SignalSender& ss);
+
+  /* CONFIG_CHANGE - controlling config change from other node */
+  void execCONFIG_CHANGE_REQ(SignalSender& ss, SimpleSignal* sig);
+  void execCONFIG_CHANGE_REF(SignalSender& ss, SimpleSignal* sig);
+  void sendConfigChangeRef(SignalSender& ss, BlockReference,
+                           ConfigChangeRef::ErrorCode) const;
+  void sendConfigChangeConf(SignalSender& ss, BlockReference) const;
+
+  /*
+    CONFIG_CHANGE_IMPL - protocol for starting config change
+    between nodes
+  */
+  void execCONFIG_CHANGE_IMPL_REQ(SignalSender& ss, SimpleSignal* sig);
+  void execCONFIG_CHANGE_IMPL_REF(SignalSender& ss, SimpleSignal* sig);
+  void execCONFIG_CHANGE_IMPL_CONF(SignalSender& ss, SimpleSignal* sig);
+  void sendConfigChangeImplRef(SignalSender& ss, NodeId nodeId,
+                               ConfigChangeRef::ErrorCode) const;
+  void sendConfigChangeImplReq(SignalSender& ss, const Config* conf);
+
+  /*
+    CONFIG_CHECK - protocol for exchanging and checking config state
+    between nodes
+  */
+  void execCONFIG_CHECK_REQ(SignalSender& ss, SimpleSignal* sig);
+  void execCONFIG_CHECK_CONF(SignalSender& ss, SimpleSignal* sig);
+  void execCONFIG_CHECK_REF(SignalSender& ss, SimpleSignal* sig);
+  void sendConfigCheckReq(SignalSender& ss, NodeBitmask to);
+  void sendConfigCheckRef(SignalSender& ss, BlockReference to,
+                          ConfigCheckRef::ErrorCode,
+                          Uint32, Uint32, ConfigState, ConfigState) const;
+  void sendConfigCheckConf(SignalSender& ss, BlockReference to) const;
+
+public:
+  ConfigManager(const MgmtSrvr::MgmtOpts&);
+  virtual ~ConfigManager();
+  bool init();
+  void set_facade(TransporterFacade* facade) { m_facade= facade; };
+  virtual void run();
+
+
+  /*
+    Installs subscriber that will be notified when
+    config has changed
+   */
+  int add_config_change_subscriber(ConfigSubscriber*);
+
+  /*
+    Retrieve the current configuration in packed format
+   */
+  bool get_packed_config(UtilBuffer& pack_buf);
+};
+
+
+
+#endif

=== added file 'storage/ndb/src/mgmsrv/ConfigSubscriber.hpp'
--- a/storage/ndb/src/mgmsrv/ConfigSubscriber.hpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/mgmsrv/ConfigSubscriber.hpp	2008-10-21 12:41:59 +0000
@@ -0,0 +1,26 @@
+/* Copyright (C) 2008 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef ConfigSubscriber_H
+#define ConfigSubscriber_H
+
+
+class ConfigSubscriber {
+public:
+  virtual void config_changed(NodeId, const class Config*)= 0;
+  virtual ~ConfigSubscriber() {};
+};
+
+#endif

=== added file 'storage/ndb/src/mgmsrv/DirIterator.cpp'
--- a/storage/ndb/src/mgmsrv/DirIterator.cpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/mgmsrv/DirIterator.cpp	2008-10-24 12:41:10 +0000
@@ -0,0 +1,122 @@
+/* Copyright (C) 2008 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include "DirIterator.hpp"
+#include <stdio.h>
+
+#ifndef __WIN__
+
+#include <dirent.h>
+
+class DirIteratorImpl {
+  DIR* m_dirp;
+
+public:
+  DirIteratorImpl():
+    m_dirp(NULL) {};
+
+  ~DirIteratorImpl() {
+    closedir(m_dirp);
+  }
+
+  int open(const char* path){
+    if ((m_dirp = opendir(path)) == NULL){
+      return -1;
+    }
+    return 0;
+  }
+
+  const char* next_file(void){
+    struct dirent* dp;
+    while ((dp = readdir(m_dirp)) != NULL &&
+           dp->d_type != DT_REG)
+      ;
+    return dp ? dp->d_name : NULL;
+  }
+};
+
+#else
+
+#include <BaseString.hpp>
+
+class DirIteratorImpl {
+  bool m_first;
+  WIN32_FIND_DATA m_find_data;
+  HANDLE m_find_handle;
+
+  bool is_dir(const WIN32_FIND_DATA find_data) const {
+    return (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+  }
+
+public:
+  DirIteratorImpl():
+    m_first(true),
+    m_find_handle(INVALID_HANDLE_VALUE) {};
+
+  ~DirIteratorImpl() {
+    FindClose(m_find_handle);
+  }
+
+  int open(const char* path){
+    BaseString path_buf;
+    path_buf.assfmt("%s\\*", path);
+    m_find_handle = FindFirstFile(path_buf.c_str(), &m_find_data);
+    if(m_find_handle == INVALID_HANDLE_VALUE)
+    {
+      if (GetLastError() == ERROR_FILE_NOT_FOUND)
+        m_first= false; // Will do a seek in 'next_file' and return NULL
+      else
+       return -1;
+    }
+    return 0;
+  }
+
+  const char* next_file(void){
+	  while(m_first || FindNextFile(m_find_handle, &m_find_data))
+    {
+      m_first= false;
+      
+	    if (!is_dir(m_find_data))
+        return m_find_data.cFileName;
+    }
+    return NULL;    
+  }
+
+};
+
+#endif
+
+
+DirIterator::DirIterator() :
+  m_impl(*new DirIteratorImpl())
+{
+};
+
+DirIterator::~DirIterator()
+{
+  delete &m_impl;
+}
+
+
+int DirIterator::open(const char* path)
+{
+  return m_impl.open(path);
+}
+
+const char* DirIterator::next_file(void)
+{
+  return m_impl.next_file();
+}
+

=== added file 'storage/ndb/src/mgmsrv/DirIterator.hpp'
--- a/storage/ndb/src/mgmsrv/DirIterator.hpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/mgmsrv/DirIterator.hpp	2008-10-24 12:41:10 +0000
@@ -0,0 +1,29 @@
+/* Copyright (C) 2008 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef DirIterator_HPP
+#define DirIterator_HPP
+
+class DirIterator {
+  class DirIteratorImpl& m_impl;
+public:
+  DirIterator();
+  ~DirIterator();
+
+  int open(const char* path);
+  const char* next_file(void);
+};
+
+#endif

=== modified file 'storage/ndb/src/mgmsrv/InitConfigFileParser.cpp'
--- a/storage/ndb/src/mgmsrv/InitConfigFileParser.cpp	2008-09-12 12:55:29 +0000
+++ b/storage/ndb/src/mgmsrv/InitConfigFileParser.cpp	2008-10-21 12:41:59 +0000
@@ -212,10 +212,8 @@ InitConfigFileParser::run_config_rules(C
   strncat(tmpLine, system, MAX_LINE_LENGTH);
   strncat(tmpLine, ":NoOfConnections", MAX_LINE_LENGTH);
   ctx.m_config->put(tmpLine, nExtConnections);
-  
-  Config * ret = new Config();
-  ret->m_configValues = (struct ndb_mgm_configuration*)ctx.m_configValues.getConfigValues();
-  return ret;
+
+  return new Config(ctx.m_configValues.getConfigValues());
 }
 
 //****************************************************************************

=== modified file 'storage/ndb/src/mgmsrv/Makefile.am'
--- a/storage/ndb/src/mgmsrv/Makefile.am	2008-10-06 06:53:04 +0000
+++ b/storage/ndb/src/mgmsrv/Makefile.am	2008-10-27 11:13:34 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2004-2006 MySQL AB
+# Copyright (C) 2004-2008 MySQL AB, 2008 Sun Microsystems, Inc.
 # 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -18,8 +18,7 @@ EXTRA_DIST = CMakeLists.txt
 MYSQLDATAdir =		$(localstatedir)
 MYSQLSHAREdir =		$(pkgdatadir)
 MYSQLBASEdir=		$(prefix)
-#MYSQLCLUSTERdir=        $(prefix)/mysql-cluster
-MYSQLCLUSTERdir=        .
+MYSQLCLUSTERdir=        $(prefix)/mysql-cluster
 
 ndbbin_PROGRAMS = ndb_mgmd
 
@@ -27,12 +26,12 @@ ndb_mgmd_SOURCES = \
 	MgmtSrvr.cpp \
 	main.cpp \
 	Services.cpp \
-	MgmtSrvrConfig.cpp \
 	ConfigInfo.cpp \
 	InitConfigFileParser.cpp \
 	Config.cpp \
-	mgm_ndbinfo.cpp
-
+	mgm_ndbinfo.cpp \
+	ConfigManager.cpp \
+	DirIterator.cpp
 
 noinst_PROGRAMS = testConfig
 

=== modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.cpp'
--- a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp	2008-10-08 14:31:38 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp	2008-10-27 11:13:34 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003 MySQL AB
+/* Copyright (C) 2003-2008 MySQL AB
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -14,11 +14,11 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 #include <ndb_global.h>
-#include <my_pthread.h>
 
 #include "MgmtSrvr.hpp"
 #include "ndb_mgmd_error.h"
 #include "Services.hpp"
+#include "ConfigManager.hpp"
 
 #include <NdbOut.hpp>
 #include <NdbApiSignal.hpp>
@@ -56,7 +56,6 @@
 #include <mgmapi.h>
 #include <mgmapi_configuration.hpp>
 #include <mgmapi_config_parameters.h>
-#include <m_string.h>
 
 #include <SignalSender.hpp>
 
@@ -89,6 +88,7 @@ static void require(bool v)
   }
 }
 
+
 void *
 MgmtSrvr::logLevelThread_C(void* m)
 {
@@ -262,11 +262,9 @@ MgmtSrvr::MgmtSrvr(const MgmtOpts& opts,
   _blockNumber(-1),
   _ownNodeId(0),
   m_port(0),
-  m_config_retriever(connect_str,
-                     NDB_VERSION,
-                     NDB_MGM_NODE_TYPE_MGM),
+  m_local_config(NULL),
   _ownReference(0),
-  _config(NULL),
+  m_config_manager(NULL),
   theFacade(NULL),
   _isStopThread(false),
   _logLevelThreadSleep(500),
@@ -276,9 +274,9 @@ MgmtSrvr::MgmtSrvr(const MgmtOpts& opts,
 {
   DBUG_ENTER("MgmtSrvr::MgmtSrvr");
 
-  m_configMutex = NdbMutex_Create();
+  m_local_config_mutex= NdbMutex_Create();
   m_node_id_mutex = NdbMutex_Create();
-  if (!m_configMutex || !m_node_id_mutex)
+  if (!m_local_config_mutex || !m_node_id_mutex)
   {
     g_eventLogger->error("Failed to create MgmtSrvr mutexes");
     require(false);
@@ -314,67 +312,66 @@ MgmtSrvr::init()
 {
   DBUG_ENTER("MgmtSrvr::init");
 
-  if (m_opts.mycnf || m_opts.config_filename)
+
+  if (!(m_config_manager= new ConfigManager(m_opts)))
   {
-    Config* conf= NULL;
-    if (m_opts.mycnf && (conf= load_init_mycnf()) == NULL)
-    {
-      g_eventLogger->error("Could not load config from 'my.cnf'");
-      DBUG_RETURN(false);
-    }
-    else if (m_opts.config_filename && (conf= load_init_config()) == NULL)
-    {
-      g_eventLogger->error("Could not load initial config from '%s'",
-                          m_opts.config_filename);
-      DBUG_RETURN(false);
-     }
-    setConfig(conf);
+    g_eventLogger->error("Failed to create ConfigManager");
+    DBUG_RETURN(false);
   }
-  else
+
+  if (m_config_manager->add_config_change_subscriber(this) < 0)
   {
-    if (fetch_config())
-    {
-      g_eventLogger->error("Could not fetch config");
-      DBUG_RETURN(false);
-    }
+    g_eventLogger->error("Failed to add MgmtSrvr as config change subscriber");
+    DBUG_RETURN(false);
   }
 
-  if (m_opts.print_full_config)
+  if (!m_config_manager->init())
   {
-    print_config();
     DBUG_RETURN(false);
   }
 
-  if (_ownNodeId == 0)
+  /* 'config_changed' should have been called from 'init' */
+  require(m_local_config);
+
+  if (m_opts.print_full_config)
   {
-    _ownNodeId= m_config_retriever.get_configuration_nodeid();
+    Guard g(m_local_config_mutex);
+    m_local_config->print();
+    DBUG_RETURN(false);
+  }
 
-    int error_code;
-    BaseString error_string;
-    if (!alloc_node_id(&_ownNodeId, NDB_MGM_NODE_TYPE_MGM,
-                       0, 0, error_code, error_string, 0))
-    {
-      g_eventLogger->error("Unable to obtain requested nodeid, error: '%s'",
-                           error_string.c_str());
-      DBUG_RETURN(false);
-    }
+  assert(_ownNodeId);
 
-    if (!m_config_retriever.verifyConfig(_config->m_configValues,
-                                         _ownNodeId))
-    {
-      g_eventLogger->error(m_config_retriever.getErrorString());
-      DBUG_RETURN(false);
-    }
+  /* Reserve the node id with ourself */
+  NodeId nodeId= _ownNodeId;
+  int error_code;
+  BaseString error_string;
+  if (!alloc_node_id(&nodeId, NDB_MGM_NODE_TYPE_MGM,
+                     0, /* client_addr */
+                     0, /* client_addr_len */
+                     error_code, error_string,
+                     0 /* log_event */ ))
+  {
+    g_eventLogger->error("INTERNAL ERROR: Could not allocate nodeid: %d, " \
+                         "error: %d, '%s'",
+                         _ownNodeId, error_code, error_string.c_str());
+    DBUG_RETURN(false);
   }
 
-  setClusterLog();
+  if (nodeId != _ownNodeId)
+  {
+    g_eventLogger->error("INTERNAL ERROR: Nodeid %d allocated " \
+                         "when %d was requested",
+                         nodeId, _ownNodeId);
+    DBUG_RETURN(false);
+  }
 
   DBUG_RETURN(true);
 }
 
 
 bool
-MgmtSrvr::start_transporter()
+MgmtSrvr::start_transporter(const Config* config)
 {
   DBUG_ENTER("MgmtSrvr::start_transporter");
 
@@ -386,7 +383,7 @@ MgmtSrvr::start_transporter()
   }
 
   if (theFacade->start_instance(_ownNodeId,
-                                _config->m_configValues) < 0)
+                                config->m_configValues) < 0)
   {
     g_eventLogger->error("Failed to start transporter");
     delete theFacade;
@@ -428,15 +425,14 @@ MgmtSrvr::start_transporter()
 
 
 bool
-MgmtSrvr::start_mgm_service()
+MgmtSrvr::start_mgm_service(const Config* config)
 {
   DBUG_ENTER("MgmtSrvr::start_mgm_service");
 
   assert(m_port == 0);
   {
     // Find the portnumber to use for mgm service
-    Guard g(m_configMutex);
-    ConfigIter iter(_config, CFG_SECTION_NODE);
+    ConfigIter iter(config, CFG_SECTION_NODE);
 
     if(iter.find(CFG_NODE_ID, _ownNodeId) != 0){
       g_eventLogger->error("Could not find node %d in config", _ownNodeId);
@@ -529,15 +525,17 @@ MgmtSrvr::start()
 {
   DBUG_ENTER("MgmtSrvr::start");
 
+  Guard g(m_local_config_mutex);
+
   /* Start transporter */
-  if(!start_transporter())
+  if(!start_transporter(m_local_config))
   {
     g_eventLogger->error("Failed to start transporter!");
     DBUG_RETURN(false);
   }
 
   /* Start mgm service */
-  if (!start_mgm_service())
+  if (!start_mgm_service(m_local_config))
   {
     g_eventLogger->error("Failed to start mangement service!");
     DBUG_RETURN(false);
@@ -550,6 +548,14 @@ MgmtSrvr::start()
     DBUG_RETURN(false);
   }
 
+  /* Start config manager */
+  m_config_manager->set_facade(theFacade);
+  if (!m_config_manager->start())
+  {
+    g_eventLogger->error("Failed to start ConfigManager");
+    DBUG_RETURN(false);
+  }
+
   /* Loglevel thread */
   assert(_isStopThread == false);
   _logLevelThread = NdbThread_Create(logLevelThread_C,
@@ -563,7 +569,7 @@ MgmtSrvr::start()
 
 
 void
-MgmtSrvr::setClusterLog(void)
+MgmtSrvr::setClusterLog(const Config* config)
 {
   BaseString logdest;
 
@@ -571,7 +577,8 @@ MgmtSrvr::setClusterLog(void)
 
   // Get log destination from config
   DBUG_ASSERT(_ownNodeId);
-  ConfigIter iter(_config, CFG_SECTION_NODE);
+
+  ConfigIter iter(config, CFG_SECTION_NODE);
   require(iter.find(CFG_NODE_ID, _ownNodeId) == 0);
 
   const char *value;
@@ -607,15 +614,26 @@ MgmtSrvr::setClusterLog(void)
 
 
 void
-MgmtSrvr::setConfig(Config* conf)
+MgmtSrvr::config_changed(NodeId node_id, const Config* new_config)
 {
-  DBUG_ENTER("MgmtSrvr::setConfig");
-  Guard g(m_configMutex);
+  DBUG_ENTER("MgmtSrvr::config_changed");
+
+  Guard g(m_local_config_mutex);
+
+  // Don't allow nodeid to change, once it's been set
+  require(_ownNodeId == 0 || _ownNodeId == node_id);
 
-  _config= conf;
+  _ownNodeId= node_id;
+
+  // TODO Magnus, Copy information about dynamic ports from
+  // new to old or save that info elsewhere
+
+  delete m_local_config;
+  m_local_config= new Config(new_config); // Copy
+  require(m_local_config);
 
   /* Rebuild node arrays */
-  ConfigIter iter(_config, CFG_SECTION_NODE);
+  ConfigIter iter(m_local_config, CFG_SECTION_NODE);
   for(Uint32 i = 0; i<MAX_NODES; i++) {
 
     m_connect_address[i].s_addr= 0;
@@ -648,13 +666,32 @@ MgmtSrvr::setConfig(Config* conf)
 
   }
 
+  setClusterLog(m_local_config);
+
+  // TODO Magnus, Reload ClusterMgr::theNodes
+
   DBUG_VOID_RETURN;
 }
 
 
+bool
+MgmtSrvr::getPackedConfig(UtilBuffer& pack_buf)
+{
+  return m_config_manager->get_packed_config(pack_buf);
+}
+
+
 MgmtSrvr::~MgmtSrvr()
 {
 
+  /* Stop config manager */
+  if (m_config_manager != 0)
+  {
+    m_config_manager->stop();
+    delete m_config_manager;
+    m_config_manager= 0;
+  }
+
   /* Stop log level thread */
   void* res = 0;
   _isStopThread = true;
@@ -677,10 +714,10 @@ MgmtSrvr::~MgmtSrvr()
     theFacade = 0;
   }
 
-  delete _config;
+  delete m_local_config;
 
+  NdbMutex_Destroy(m_local_config_mutex);
   NdbMutex_Destroy(m_node_id_mutex);
-  NdbMutex_Destroy(m_configMutex);
 }
 
 
@@ -701,13 +738,16 @@ int MgmtSrvr::okToSendTo(NodeId nodeId, 
   return NO_CONTACT_WITH_PROCESS;
 }
 
-void report_unknown_signal(SimpleSignal *signal)
+void
+MgmtSrvr::report_unknown_signal(SimpleSignal *signal)
 {
+  signal->print();
   g_eventLogger->error("Unknown signal received. SignalNumber: "
-                       "%i from (%d, %x)",
+                       "%i from (%d, 0x%x)",
                        signal->readSignalNumber(),
                        refToNode(signal->header.theSendersBlockRef),
                        refToBlock(signal->header.theSendersBlockRef));
+  assert(false);
 }
 
 /*****************************************************************************
@@ -754,8 +794,8 @@ MgmtSrvr::versionNode(int nodeId, Uint32
     mysql_version = NDB_MYSQL_VERSION_D;
     if(!*address)
     {
-      ndb_mgm_configuration_iterator
-	iter(*_config->m_configValues, CFG_SECTION_NODE);
+      Guard g(m_local_config_mutex);
+      ConfigIter iter(m_local_config, CFG_SECTION_NODE);
       unsigned tmp= 0;
       for(iter.first();iter.valid();iter.next())
       {
@@ -786,9 +826,10 @@ MgmtSrvr::versionNode(int nodeId, Uint32
   return 0;
 }
 
-int 
-MgmtSrvr::sendVersionReq(int v_nodeId, 
-			 Uint32 &version, 
+
+int
+MgmtSrvr::sendVersionReq(int v_nodeId,
+			 Uint32 &version,
 			 Uint32& mysql_version,
 			 const char **address)
 {
@@ -799,49 +840,38 @@ MgmtSrvr::sendVersionReq(int v_nodeId, 
   ApiVersionReq* req = CAST_PTR(ApiVersionReq, ssig.getDataPtrSend());
   req->senderRef = ss.getOwnRef();
   req->nodeId = v_nodeId;
-  ssig.set(ss, TestOrd::TraceAPI, QMGR, GSN_API_VERSION_REQ, 
-	   ApiVersionReq::SignalLength);
+  ssig.set(ss, TestOrd::TraceAPI, QMGR,
+           GSN_API_VERSION_REQ, ApiVersionReq::SignalLength);
 
-  int do_send = 1;
   NodeId nodeId;
-
-  while (1)
+  int do_send = 1;
+  while(true)
   {
     if (do_send)
     {
-      bool next;
-      nodeId = 0;
-
-      while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
-	    okToSendTo(nodeId, true) != 0);
-
-      const ClusterMgr::Node &node=
-	theFacade->theClusterMgr->getNodeInfo(nodeId);
-      if(next && node.m_state.startLevel != NodeState::SL_STARTED)
+      nodeId = ss.get_an_alive_node();
+      if (nodeId == 0)
       {
-	NodeId tmp=nodeId;
-	while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
-	      okToSendTo(nodeId, true) != 0);
-	if(!next)
-	  nodeId= tmp;
+        return NO_CONTACT_WITH_DB_NODES;
       }
 
-      if(!next) return NO_CONTACT_WITH_DB_NODES;
-
-      if (ss.sendSignal(nodeId, &ssig) != SEND_OK) {
-	return SEND_OR_RECEIVE_FAILED;
+      if (ss.sendSignal(nodeId, &ssig) != SEND_OK)
+      {
+        return SEND_OR_RECEIVE_FAILED;
       }
+
       do_send = 0;
     }
 
     SimpleSignal *signal = ss.waitFor();
 
-    int gsn = signal->readSignalNumber();
-    switch (gsn) {
+    switch (signal->readSignalNumber()) {
     case GSN_API_VERSION_CONF: {
-      const ApiVersionConf * const conf = 
+      const ApiVersionConf * const conf =
 	CAST_CONSTPTR(ApiVersionConf, signal->getDataPtr());
+
       assert((int) conf->nodeId == v_nodeId);
+
       version = conf->version;
       mysql_version = conf->mysql_version;
       if (version < NDBD_SPLIT_VERSION)
@@ -849,8 +879,10 @@ MgmtSrvr::sendVersionReq(int v_nodeId, 
       struct in_addr in;
       in.s_addr= conf->inet_addr;
       *address= inet_ntoa(in);
+
       return 0;
     }
+
     case GSN_NF_COMPLETEREP:{
       const NFCompleteRep * const rep =
 	CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr());
@@ -858,6 +890,7 @@ MgmtSrvr::sendVersionReq(int v_nodeId, 
 	do_send = 1; // retry with other node
       continue;
     }
+
     case GSN_NODE_FAILREP:{
       const NodeFailRep * const rep =
 	CAST_CONSTPTR(NodeFailRep, signal->getDataPtr());
@@ -865,16 +898,23 @@ MgmtSrvr::sendVersionReq(int v_nodeId, 
 	do_send = 1; // retry with other node
       continue;
     }
+
+    case GSN_API_REGCONF:
+      // Ignore
+      continue;
+
     default:
       report_unknown_signal(signal);
       return SEND_OR_RECEIVE_FAILED;
     }
-    break;
-  } // while(1)
+  }
 
-  return 0;
+  // Should never come here
+  require(false);
+  return -1;
 }
 
+
 int MgmtSrvr::sendStopMgmd(NodeId nodeId,
 			   bool abort,
 			   bool stop,
@@ -887,18 +927,16 @@ int MgmtSrvr::sendStopMgmd(NodeId nodeId
   BaseString connect_string;
 
   {
-    Guard g(m_configMutex);
+    Guard g(m_local_config_mutex);
     {
-      ndb_mgm_configuration_iterator
-        iter(* _config->m_configValues, CFG_SECTION_NODE);
+      ConfigIter iter(m_local_config, CFG_SECTION_NODE);
 
       if(iter.first())                       return SEND_OR_RECEIVE_FAILED;
       if(iter.find(CFG_NODE_ID, nodeId))     return SEND_OR_RECEIVE_FAILED;
       if(iter.get(CFG_NODE_HOST, &hostname)) return SEND_OR_RECEIVE_FAILED;
     }
     {
-      ndb_mgm_configuration_iterator
-        iter(* _config->m_configValues, CFG_SECTION_NODE);
+      ConfigIter iter(m_local_config, CFG_SECTION_NODE);
 
       if(iter.first())                   return SEND_OR_RECEIVE_FAILED;
       if(iter.find(CFG_NODE_ID, nodeId)) return SEND_OR_RECEIVE_FAILED;
@@ -906,6 +944,7 @@ int MgmtSrvr::sendStopMgmd(NodeId nodeId
     }
     if( strlen(hostname) == 0 )
       return SEND_OR_RECEIVE_FAILED;
+
   }
   connect_string.assfmt("%s:%u",hostname,port);
 
@@ -1179,6 +1218,8 @@ int MgmtSrvr::sendSTOP_REQ(const Vector<
 	stoppedNodes.bitOR(mask);
       break;
     }
+    case GSN_API_REGCONF:
+      break;
     default:
       report_unknown_signal(signal);
 #ifdef VM_TRACE
@@ -1503,6 +1544,7 @@ MgmtSrvr::exitSingleUser(int * stopCount
   SimpleSignal ssig;
   ResumeReq* const resumeReq = 
     CAST_PTR(ResumeReq, ssig.getDataPtrSend());
+
   ssig.set(ss,TestOrd::TraceAPI, NDBCNTR, GSN_RESUME_REQ, 
 	   ResumeReq::SignalLength);
   resumeReq->senderData = 12;
@@ -1739,6 +1781,8 @@ MgmtSrvr::setEventReportingLevelImpl(int
       nodes.clear(rep->failedNodeId);
       break;
     }
+    case GSN_API_REGCONF:
+      break;
     default:
       report_unknown_signal(signal);
       return SEND_OR_RECEIVE_FAILED;
@@ -1803,6 +1847,7 @@ MgmtSrvr::insertError(int nodeId, int er
   return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED;
 }
 
+
 int
 MgmtSrvr::startSchemaTrans(SignalSender& ss, NodeId & out_nodeId,
                            Uint32 transId, Uint32 & out_transKey)
@@ -1872,6 +1917,8 @@ retry:
       }
       break;
     }
+    case GSN_API_REGCONF:
+      break;
     default:
       report_unknown_signal(signal);
       return SEND_OR_RECEIVE_FAILED;
@@ -1928,6 +1975,8 @@ MgmtSrvr::endSchemaTrans(SignalSender& s
       }
       break;
     }
+    case GSN_API_REGCONF:
+      break;
     default:
       report_unknown_signal(signal);
       return SEND_OR_RECEIVE_FAILED;
@@ -2019,6 +2068,8 @@ MgmtSrvr::createNodegroup(int *nodes, in
       }
       break;
     }
+    case GSN_API_REGCONF:
+      break;
     default:
       report_unknown_signal(signal);
       return SEND_OR_RECEIVE_FAILED;
@@ -2091,6 +2142,8 @@ MgmtSrvr::dropNodegroup(int ng)
       }
       break;
     }
+    case GSN_API_REGCONF:
+      break;
     default:
       report_unknown_signal(signal);
       return SEND_OR_RECEIVE_FAILED;
@@ -2372,10 +2425,6 @@ MgmtSrvr::handleReceivedSignal(NdbApiSig
   int gsn = signal->readSignalNumber();
 
   switch (gsn) {
-  case GSN_EVENT_SUBSCRIBE_CONF:
-    break;
-  case GSN_EVENT_SUBSCRIBE_REF:
-    break;
   case GSN_EVENT_REP:
   {
     eventReport(signal->getDataPtr(), signal->getLength());
@@ -2390,6 +2439,8 @@ MgmtSrvr::handleReceivedSignal(NdbApiSig
   case GSN_TAMPER_ORD:
     ndbout << "TAMPER ORD" << endl;
     break;
+  case GSN_API_REGCONF:
+    break;
 
   case GSN_DBINFO_SCANREQ:
     execDBINFO_SCANREQ(signal);
@@ -2397,10 +2448,11 @@ MgmtSrvr::handleReceivedSignal(NdbApiSig
 
   default:
     g_eventLogger->error("Unknown signal received. SignalNumber: "
-                         "%i from (%d, %x)",
+                         "%i from (%d, 0x%x)",
                          gsn,
                          refToNode(signal->theSendersBlockRef),
                          refToBlock(signal->theSendersBlockRef));
+    assert(false);
   }
 }
 
@@ -2482,7 +2534,7 @@ const char *MgmtSrvr::get_connect_addres
 void
 MgmtSrvr::get_connected_nodes(NodeBitmask &connected_nodes) const
 {
-  if (theFacade && theFacade->theClusterMgr) 
+  if (theFacade && theFacade->theClusterMgr)
   {
     for(Uint32 i = 0; i < MAX_NDB_NODES; i++)
     {
@@ -2583,6 +2635,8 @@ MgmtSrvr::alloc_node_id_req(NodeId free_
       // ignore NF_COMPLETEREP will come
       continue;
     }
+    case GSN_API_REGCONF:
+      break;
     default:
       report_unknown_signal(signal);
       return SEND_OR_RECEIVE_FAILED;
@@ -2629,15 +2683,8 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId,
   int r_config_addr= -1;
   unsigned type_c= 0;
 
-  if(NdbMutex_Lock(m_configMutex))
-  {
-    // should not happen
-    error_string.appfmt("unable to lock configuration mutex");
-    error_code = NDB_MGM_ALLOCID_ERROR;
-    DBUG_RETURN(false);
-  }
-  ndb_mgm_configuration_iterator
-    iter(* _config->m_configValues, CFG_SECTION_NODE);
+  NdbMutex_Lock(m_local_config_mutex);
+  ConfigIter iter(m_local_config, CFG_SECTION_NODE);
   for(iter.first(); iter.valid(); iter.next()) {
     unsigned tmp= 0;
     if(iter.get(CFG_NODE_ID, &tmp)) require(false);
@@ -2704,7 +2751,7 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId,
 			  "Suggest specifying node id in connectstring,\n"
 			  "or specifying unique host names in config file.",
 			  id_found, tmp);
-      NdbMutex_Unlock(m_configMutex);
+      NdbMutex_Unlock(m_local_config_mutex);
       error_code = NDB_MGM_ALLOCID_CONFIG_MISMATCH;
       DBUG_RETURN(false);
     }
@@ -2714,13 +2761,13 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId,
 			  "or specifying unique host names in config file,\n"
 			  "or specifying just one mgmt server in config file.",
 			  tmp);
-      NdbMutex_Unlock(m_configMutex);
+      NdbMutex_Unlock(m_local_config_mutex);
       error_code = NDB_MGM_ALLOCID_CONFIG_MISMATCH;
       DBUG_RETURN(false);
     }
     id_found= tmp; // mgmt server matched, check for more matches
   }
-  NdbMutex_Unlock(m_configMutex);
+  NdbMutex_Unlock(m_local_config_mutex);
 
   if (id_found && client_addr != 0)
   {
@@ -2986,12 +3033,12 @@ MgmtSrvr::startBackup(Uint32& backupId, 
   BlockNumber backupBlockNo = numberToBlock(BACKUP, 1);
   if(input_backupId > 0)
   {
-    ssig.set(ss, TestOrd::TraceAPI, backupBlockNo, GSN_BACKUP_REQ, 
+    ssig.set(ss, TestOrd::TraceAPI, backupBlockNo, GSN_BACKUP_REQ,
 	     BackupReq::SignalLength);
     req->inputBackupId = input_backupId;
   }
   else
-    ssig.set(ss, TestOrd::TraceAPI, backupBlockNo, GSN_BACKUP_REQ, 
+    ssig.set(ss, TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ, 
 	     BackupReq::SignalLength - 1);
   
   req->senderData = 19;
@@ -3109,6 +3156,8 @@ MgmtSrvr::startBackup(Uint32& backupId, 
       // master node will report aborted backup
       break;
     }
+    case GSN_API_REGCONF:
+      break;
     default:
       report_unknown_signal(signal);
       return SEND_OR_RECEIVE_FAILED;
@@ -3199,50 +3248,44 @@ MgmtSrvr::Allocated_resources::get_nodei
 
 int
 MgmtSrvr::setDbParameter(int node, int param, const char * value,
-			 BaseString& msg){
+			 BaseString& msg)
+{
 
-  if(NdbMutex_Lock(m_configMutex))
-    return -1;
+  Guard g(m_local_config_mutex);
 
   /**
    * Check parameter
    */
-  ndb_mgm_configuration_iterator
-    iter(* _config->m_configValues, CFG_SECTION_NODE);
+  ConfigIter iter(m_local_config, CFG_SECTION_NODE);
   if(iter.first() != 0){
     msg.assign("Unable to find node section (iter.first())");
-    NdbMutex_Unlock(m_configMutex);
     return -1;
   }
-  
+
   Uint32 type = NODE_TYPE_DB + 1;
   if(node != 0){
     if(iter.find(CFG_NODE_ID, node) != 0){
       msg.assign("Unable to find node (iter.find())");
-      NdbMutex_Unlock(m_configMutex);
       return -1;
     }
     if(iter.get(CFG_TYPE_OF_SECTION, &type) != 0){
       msg.assign("Unable to get node type(iter.get(CFG_TYPE_OF_SECTION))");
-      NdbMutex_Unlock(m_configMutex);
       return -1;
     }
   } else {
     do {
       if(iter.get(CFG_TYPE_OF_SECTION, &type) != 0){
 	msg.assign("Unable to get node type(iter.get(CFG_TYPE_OF_SECTION))");
-	NdbMutex_Unlock(m_configMutex);
 	return -1;
       }
       if(type == NODE_TYPE_DB)
 	break;
     } while(iter.next() == 0);
   }
-  
+
   if(type != NODE_TYPE_DB){
     msg.assfmt("Invalid node type or no such node (%d %d)", 
 	       type, NODE_TYPE_DB);
-    NdbMutex_Unlock(m_configMutex);
     return -1;
   }
 
@@ -3256,7 +3299,7 @@ MgmtSrvr::setDbParameter(int node, int p
       val_32 = atoi(value);
       break;
     }
-    
+
     p_type++;
     if(iter.get(param, &val_64) == 0){
       val_64 = strtoll(value, 0, 10);
@@ -3268,23 +3311,22 @@ MgmtSrvr::setDbParameter(int node, int p
       break;
     }
     msg.assign("Could not get parameter");
-    NdbMutex_Unlock(m_configMutex);
     return -1;
   } while(0);
-  
+
   bool res = false;
   do {
     int ret = iter.get(CFG_TYPE_OF_SECTION, &type);
     assert(ret == 0);
-    
+
     if(type != NODE_TYPE_DB)
       continue;
-    
+
     Uint32 node;
     ret = iter.get(CFG_NODE_ID, &node);
     assert(ret == 0);
-    
-    ConfigValues::Iterator i2(_config->m_configValues->m_config, 
+
+    ConfigValues::Iterator i2(m_local_config->m_configValues->m_config, 
 			      iter.m_config);
     switch(p_type){
     case 0:
@@ -3306,30 +3348,25 @@ MgmtSrvr::setDbParameter(int node, int p
   } while(node == 0 && iter.next() == 0);
 
   msg.assign("Success");
-  NdbMutex_Unlock(m_configMutex);
   return 0;
 }
+
+
 int
 MgmtSrvr::setConnectionDbParameter(int node1, 
 				   int node2,
 				   int param,
 				   int value,
-				   BaseString& msg){
-  Uint32 current_value,new_value;
-
+				   BaseString& msg)
+{
   DBUG_ENTER("MgmtSrvr::setConnectionDbParameter");
 
-  if(NdbMutex_Lock(m_configMutex))
-  {
-    DBUG_RETURN(-1);
-  }
-
-  ndb_mgm_configuration_iterator 
-    iter(* _config->m_configValues, CFG_SECTION_CONNECTION);
+  Uint32 current_value,new_value;
+  Guard g(m_local_config_mutex);
+  ConfigIter iter(m_local_config, CFG_SECTION_CONNECTION);
 
   if(iter.first() != 0){
     msg.assign("Unable to find connection section (iter.first())");
-    NdbMutex_Unlock(m_configMutex);
     DBUG_RETURN(-1);
   }
 
@@ -3343,33 +3380,32 @@ MgmtSrvr::setConnectionDbParameter(int n
   }
   if(!iter.valid()) {
     msg.assign("Unable to find connection between nodes");
-    NdbMutex_Unlock(m_configMutex);
     DBUG_RETURN(-2);
   }
-  
+
   if(iter.get(param, &current_value) != 0) {
     msg.assign("Unable to get current value of parameter");
-    NdbMutex_Unlock(m_configMutex);
     DBUG_RETURN(-3);
   }
 
-  ConfigValues::Iterator i2(_config->m_configValues->m_config,
+  ConfigValues::Iterator i2(m_local_config->m_configValues->m_config,
 			    iter.m_config);
 
   if(i2.set(param, (unsigned)value) == false) {
     msg.assign("Unable to set new value of parameter");
-    NdbMutex_Unlock(m_configMutex);
     DBUG_RETURN(-4);
   }
-  
+
+  // TODO Magnus, in theory this new config should be saved on
+  // nodes, but it's probably a better idea to save this
+  // dynamic information elsewhere instead.
+
   if(iter.get(param, &new_value) != 0) {
     msg.assign("Unable to get parameter after setting it.");
-    NdbMutex_Unlock(m_configMutex);
     DBUG_RETURN(-5);
   }
 
   msg.assfmt("%u -> %u",current_value,new_value);
-  NdbMutex_Unlock(m_configMutex);
   DBUG_RETURN(1);
 }
 
@@ -3379,20 +3415,15 @@ MgmtSrvr::getConnectionDbParameter(int n
 				   int node2,
 				   int param,
 				   int *value,
-				   BaseString& msg){
-  DBUG_ENTER("MgmtSrvr::getConnectionDbParameter");
-
-  if(NdbMutex_Lock(m_configMutex))
-  {
-    DBUG_RETURN(-1);
-  }
+				   BaseString& msg)
+{
 
-  ndb_mgm_configuration_iterator
-    iter(* _config->m_configValues, CFG_SECTION_CONNECTION);
+  DBUG_ENTER("MgmtSrvr::getConnectionDbParameter");
+  Guard g(m_local_config_mutex);
+  ConfigIter iter(m_local_config, CFG_SECTION_CONNECTION);
 
   if(iter.first() != 0){
     msg.assign("Unable to find connection section (iter.first())");
-    NdbMutex_Unlock(m_configMutex);
     DBUG_RETURN(-1);
   }
 
@@ -3406,21 +3437,20 @@ MgmtSrvr::getConnectionDbParameter(int n
   }
   if(!iter.valid()) {
     msg.assign("Unable to find connection between nodes");
-    NdbMutex_Unlock(m_configMutex);
     DBUG_RETURN(-1);
   }
-  
+
   if(iter.get(param, (Uint32*)value) != 0) {
     msg.assign("Unable to get current value of parameter");
-    NdbMutex_Unlock(m_configMutex);
     DBUG_RETURN(-1);
   }
 
   msg.assfmt("%d",*value);
-  NdbMutex_Unlock(m_configMutex);
+
   DBUG_RETURN(1);
 }
 
+
 void MgmtSrvr::transporter_connect(NDB_SOCKET_TYPE sockfd)
 {
   if (theFacade->get_registry()->connect_server(sockfd))

=== modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.hpp'
--- a/storage/ndb/src/mgmsrv/MgmtSrvr.hpp	2008-10-07 06:47:09 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.hpp	2008-10-27 11:13:34 +0000
@@ -17,9 +17,9 @@
 #define MgmtSrvr_H
 
 #include "Config.hpp"
-#include <mgmapi.h>
+#include "ConfigSubscriber.hpp"
 
-#include <ConfigRetriever.hpp>
+#include <mgmapi.h>
 #include <Vector.hpp>
 #include <NodeBitmask.hpp>
 #include <ndb_version.h>
@@ -70,8 +70,8 @@ public:
   @class MgmtSrvr
   @brief Main class for the management server.
  */
-class MgmtSrvr {
-  
+class MgmtSrvr : private ConfigSubscriber {
+
 public:
   // some compilers need all of this
   class Allocated_resources;
@@ -130,6 +130,7 @@ public:
     const char* bind_address;
     int no_nodeid_checks;
     int print_full_config;
+    const char* datadir;
   };
 
   MgmtSrvr(); // Not implemented
@@ -139,21 +140,10 @@ public:
   ~MgmtSrvr();
 
   /*
-    To be called after constructor. Loads configuration
-    from disk or fetches it from other server
-   */
+    To be called after constructor.
+  */
   bool init();
 
-private:
-  /* Functions used from 'init' */
-  Config* load_init_config(void);
-  Config* load_init_mycnf(void);
-  bool fetch_config(void);
-  bool save_config(const Config* conf);
-  bool save_config(void);
-
-public:
-
   /*
     To be called after 'init', starts up the services
     this server will expose
@@ -161,16 +151,14 @@ public:
   bool start(void);
 private:
   /* Functions used from 'start' */
-  bool start_transporter(void);
-  bool start_mgm_service(void);
+  bool start_transporter(const Config*);
+  bool start_mgm_service(const Config*);
   bool connect_to_self(void);
 
 public:
 
   NodeId getOwnNodeId() const {return _ownNodeId;};
 
-  void print_config() { _config->print(); };
-
   /**
    * Get status on a node.
    * address may point to a common area (e.g. from inet_addr)
@@ -205,15 +193,6 @@ public:
   int shutdownDB(int * cnt = 0, bool abort = false);
 
   /**
-   *   print version info about a node
-   * 
-   *   @param   processId: Id of the DB process to stop
-   *   @return  0 if succeeded, otherwise: as stated above, plus:
-   */
-  int versionNode(int nodeId, Uint32 &version, Uint32 &mysql_version,
-		  const char **address);
-
-  /**
    *   Maintenance on the system
    */
   int enterSingleUser(int * cnt = 0, Uint32 singleuserNodeId = 0);
@@ -390,13 +369,9 @@ public:
    */
   const char* getErrorText(int errorCode, char *buf, int buf_sz);
 
-  /**
-   *   Get configuration
-   */
-  const Config * getConfig() const;
 private:
-  void setConfig(Config* conf);
-  void setClusterLog(void);
+  void config_changed(NodeId, const Config*);
+  void setClusterLog(const Config* conf);
 public:
 
   /**
@@ -429,6 +404,12 @@ public:
 
 private:
 
+  int versionNode(int nodeId, Uint32 &version,
+                  Uint32 &mysql_version, const char **address);
+
+  int sendVersionReq(int processId, Uint32 &version,
+                     Uint32& mysql_version, const char **address);
+
   int sendStopMgmd(NodeId nodeId,
                    bool abort,
                    bool stop,
@@ -483,15 +464,17 @@ private:
   NodeId _ownNodeId;
   Uint32 m_port;
   SocketServer m_socket_server;
-  ConfigRetriever m_config_retriever;
 
   Vector<BaseString> m_ndbinfo_table_names;
   Vector< Vector<Uint32> > m_ndbinfo_column_types;
   Vector< Vector<BaseString> > m_ndbinfo_column_names;
 
-  BlockReference _ownReference; 
-  NdbMutex *m_configMutex;
-  const Config * _config;
+  NdbMutex* m_local_config_mutex;
+  const Config* m_local_config;
+
+  BlockReference _ownReference;
+
+  class ConfigManager* m_config_manager;
 
   NodeBitmask m_reserved_nodes;
   struct in_addr m_connect_address[MAX_NODES];
@@ -529,8 +512,6 @@ private:
  
   class TransporterFacade * theFacade;
 
-  int  sendVersionReq( int processId, Uint32 &version, Uint32& mysql_version,
-		       const char **address);
   int translateStopRef(Uint32 errCode);
   
   bool _isStopThread;
@@ -552,12 +533,17 @@ private:
   struct NdbThread* _logLevelThread;
   static void *logLevelThread_C(void *);
   void logLevelThreadRun();
+
+  void report_unknown_signal(SimpleSignal *signal);
+
+
+public:
+  /*
+    Get packed copy of configuration in the supplied buffer
+  */
+  bool getPackedConfig(UtilBuffer& pack_buf);
+
 };
 
-inline
-const Config *
-MgmtSrvr::getConfig() const {
-  return _config;
-}
 
 #endif // MgmtSrvr_H

=== removed file 'storage/ndb/src/mgmsrv/MgmtSrvrConfig.cpp'
--- a/storage/ndb/src/mgmsrv/MgmtSrvrConfig.cpp	2008-08-04 21:01:04 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtSrvrConfig.cpp	1970-01-01 00:00:00 +0000
@@ -1,81 +0,0 @@
-/* Copyright (C) 2003 MySQL AB
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; version 2 of the License.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-
-#include "MgmtSrvr.hpp"
-#include <InitConfigFileParser.hpp>
-#include <ConfigRetriever.hpp>
-#include <NdbSleep.h>
-
-
-Config*
-MgmtSrvr::load_init_config(void)
-{
-   InitConfigFileParser parser;
-   g_eventLogger->info("Reading cluster configuration from '%s'",
-                      m_opts.config_filename);
-  return parser.parseConfig(m_opts.config_filename);
-}
-
-
-Config*
-MgmtSrvr::load_init_mycnf(void)
-{
-  InitConfigFileParser parser;
-  g_eventLogger->info("Reading cluster configuration using my.cnf");
-  return parser.parse_mycnf();
-}
-
-
-bool
-MgmtSrvr::fetch_config(void)
-{
-  char buf[128];
-  DBUG_ENTER("MgmtSrvr::fetch_config");
-  assert(_config == NULL);
-
-  /* Loop until config loaded from other mgmd(s) */
-  g_eventLogger->info("Trying to get configuration from other mgmd(s)"\
-                     "using '%.128s'...",
-                     m_config_retriever.get_connectstring(buf, sizeof(buf)));
-
-
-  int retry= 0, delay= 0, verbose= 1;
-  while (m_config_retriever.do_connect(retry, delay, verbose) != 0) {
-    g_eventLogger->info("Waiting for connection to other mgmd(s)...");
-    NdbSleep_SecSleep(1);
-  }
-  g_eventLogger->info("Connected...");
-
-  // "login" and alloc node id from the other mgmd
-  _ownNodeId= m_config_retriever.allocNodeId(retry, delay);
-  if (_ownNodeId == 0) {
-    g_eventLogger->error(m_config_retriever.getErrorString());
-    DBUG_RETURN(false);
-  }
-
-  // read config from other managent server
-  struct ndb_mgm_configuration * tmp = m_config_retriever.getConfig();
-  if (tmp == NULL) {
-    g_eventLogger->error(m_config_retriever.getErrorString());
-    DBUG_RETURN(false);
-  }
-
-  setConfig(new Config(tmp));
-
-  DBUG_RETURN(true);
-}
-
-
-

=== added file 'storage/ndb/src/mgmsrv/MgmtThread.hpp'
--- a/storage/ndb/src/mgmsrv/MgmtThread.hpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtThread.hpp	2008-10-21 12:41:59 +0000
@@ -0,0 +1,73 @@
+/* Copyright (C) 2008 Sun Microsystems, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef MgmtThread_H
+#define MgmtThread_H
+
+#include <ndb_global.h>
+#include <NdbThread.h>
+
+class MgmtThread {
+  bool m_running;
+  const char* m_name;
+  size_t m_stack_size;
+  NDB_THREAD_PRIO m_thread_prio;
+  struct NdbThread* m_thread;
+
+  static void* run_C(void* t) {
+    MgmtThread *thread = (MgmtThread*)t;
+    thread->run();
+    return 0;
+  }
+public:
+  MgmtThread(); // Not implemented
+  MgmtThread(const MgmtThread&); // Not implemented
+  MgmtThread(const char* name,
+             size_t stack_size= 32768,
+             NDB_THREAD_PRIO thread_prio= NDB_THREAD_PRIO_LOW) :
+    m_running(true),
+    m_name(name),
+    m_stack_size(stack_size),
+    m_thread_prio(thread_prio),
+    m_thread(NULL){
+  };
+  virtual ~MgmtThread() {
+    if (m_thread)
+      stop();
+  };
+
+  virtual void run()= 0;
+  bool start(){
+    assert(m_running);
+    m_thread = NdbThread_Create(run_C, (void**)this, m_stack_size,
+                                m_name, m_thread_prio);
+    return (m_thread != NULL);
+  }
+  bool stop(){
+    void* res = 0;
+    if (!m_thread)
+      return false;
+
+    m_running= false;
+
+    NdbThread_WaitFor(m_thread, &res);
+    NdbThread_Destroy(&m_thread);
+    return true;
+
+  }
+  bool is_stopped() { return !m_running; };
+};
+
+#endif

=== modified file 'storage/ndb/src/mgmsrv/Services.cpp'
--- a/storage/ndb/src/mgmsrv/Services.cpp	2008-10-08 09:33:48 +0000
+++ b/storage/ndb/src/mgmsrv/Services.cpp	2008-10-27 11:13:34 +0000
@@ -620,14 +620,6 @@ MgmApiSession::getConfig(Parser_t::Conte
   args.get("version", &version);
   args.get("node", &node);
 
-  const Config *conf = m_mgmsrv.getConfig();
-  if(conf == NULL) {
-    m_output->println("get config reply");
-    m_output->println("result: Could not fetch configuration");
-    m_output->println("");
-    return;
-  }
-
   if(node != 0){
     bool compatible;
     switch (m_mgmsrv.getNodeType(node)) {
@@ -653,16 +645,19 @@ MgmApiSession::getConfig(Parser_t::Conte
       return;
     }
   }  
-  
-  NdbMutex_Lock(m_mgmsrv.m_configMutex);
-  const ConfigValues * cfg = &conf->m_configValues->m_config;
-  
-  UtilBuffer src;
-  cfg->pack(src);
-  NdbMutex_Unlock(m_mgmsrv.m_configMutex);
-  
-  char *tmp_str = (char *) malloc(base64_needed_encoded_length(src.length()));
-  (void) base64_encode(src.get_data(), src.length(), tmp_str);
+
+  UtilBuffer packed;
+  if (!m_mgmsrv.getPackedConfig(packed))
+  {
+    m_output->println("get config reply");
+    m_output->println("result: Could not fetch configuration");
+    m_output->println("");
+    return;
+  }
+
+  char *tmp_str =
+    (char *) malloc(base64_needed_encoded_length(packed.length()));
+  (void) base64_encode(packed.get_data(), packed.length(), tmp_str);
 
   SLEEP_ERROR_INSERTED(1);
 
@@ -2068,6 +2063,14 @@ void MgmApiSession::getNdbInfo(Parser_t:
   return ;
 }
 
+#if 0
+  // TODO Magnus, "get variables"
+  ndbout_c("NdbConfig_get_path(0): %s", NdbConfig_get_path(0));
+  ndbout_c("opt_ndb_connectstring: %s", opt_ndb_connectstring);
+  ndbout_c("NDB_CONNECTSTRING: %s", getenv("NDB_CONNECTSTRING"));
+  ndbout_c("datadir: %s", opts.datadir);
+#endif
+
 template class MutexVector<int>;
 template class Vector<ParserRow<MgmApiSession> const*>;
 template class Vector<NDB_SOCKET_TYPE>;

=== modified file 'storage/ndb/src/mgmsrv/main.cpp'
--- a/storage/ndb/src/mgmsrv/main.cpp	2008-10-03 08:22:13 +0000
+++ b/storage/ndb/src/mgmsrv/main.cpp	2008-10-21 12:41:59 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003 MySQL AB
+/* Copyright (C) 2003-2008 MySQL AB, 2008 Sun Microsystems, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -115,6 +115,10 @@ static struct my_option my_long_options[
     "Local bind address",
     (uchar**) &opts.bind_address, (uchar**) &opts.bind_address, 0,
     GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+  { "datadir", 256,
+    "Data directory for this node",
+    (uchar**) &opts.datadir, (uchar**) &opts.datadir, 0,
+    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 };
 
@@ -161,12 +165,14 @@ int main(int argc, char** argv)
     exit(1);
   }
 
-  if (opts.mycnf == 0 && opts.config_filename == 0)
-  {
-    MY_STAT buf;
-    if (my_stat("config.ini", &buf, MYF(0)) != NULL)
-      opts.config_filename = "config.ini";
-  }
+  /**
+     Install signal handler for SIGPIPE
+     Done in TransporterFacade as well.. what about Configretriever?
+   */
+#if !defined NDB_WIN32
+  signal(SIGPIPE, SIG_IGN);
+#endif
+
 start:
 
   g_eventLogger->info("NDB Cluster Management Server. %s", NDB_VERSION_STRING);
@@ -177,14 +183,6 @@ start:
     exit(1);
   }
 
-  /**
-     Install signal handler for SIGPIPE
-     Done in TransporterFacade as well.. what about Configretriever?
-   */
-#if !defined NDB_WIN32
-  signal(SIGPIPE, SIG_IGN);
-#endif
-
   /* Init mgm, load or fetch config */
   if (!mgm->init()) {
     delete mgm;

=== modified file 'storage/ndb/src/ndbapi/ClusterMgr.cpp'
--- a/storage/ndb/src/ndbapi/ClusterMgr.cpp	2008-08-21 06:33:53 +0000
+++ b/storage/ndb/src/ndbapi/ClusterMgr.cpp	2008-10-21 12:41:59 +0000
@@ -221,7 +221,6 @@ ClusterMgr::threadMain( ){
   NdbApiSignal signal(numberToRef(API_CLUSTERMGR, theFacade.ownId()));
   
   signal.theVerId_signalNumber   = GSN_API_REGREQ;
-  signal.theReceiversBlockNumber = QMGR;
   signal.theTrace                = 0;
   signal.theLength               = ApiRegReq::SignalLength;
 
@@ -280,6 +279,11 @@ ClusterMgr::threadMain( ){
 	  theNode.hbCounter = 0;
 	}
 
+        if(theNode.m_info.m_type == NodeInfo::MGM)
+          signal.theReceiversBlockNumber = API_CLUSTERMGR;
+        else
+          signal.theReceiversBlockNumber = QMGR;
+
 #ifdef DEBUG_REG
 	ndbout_c("ClusterMgr: Sending API_REGREQ to node %d", (int)nodeId);
 #endif
@@ -365,7 +369,8 @@ ClusterMgr::execAPI_REGREQ(const Uint32 
   conf->version = NDB_VERSION;
   conf->mysql_version = NDB_MYSQL_VERSION_D;
   conf->apiHeartbeatFrequency = node.hbFrequency;
-  theFacade.sendSignalUnCond(&signal, nodeId);
+  if (theFacade.sendSignalUnCond(&signal, nodeId) == SEND_OK)
+    node.m_api_reg_conf= true;
 }
 
 void

=== modified file 'storage/ndb/src/ndbapi/SignalSender.cpp'
--- a/storage/ndb/src/ndbapi/SignalSender.cpp	2008-10-02 07:51:11 +0000
+++ b/storage/ndb/src/ndbapi/SignalSender.cpp	2008-10-27 11:13:34 +0000
@@ -18,6 +18,7 @@
 #include <SignalLoggerManager.hpp>
 #include <signaldata/NFCompleteRep.hpp>
 #include <signaldata/NodeFailRep.hpp>
+#include <signaldata/TestOrd.hpp>
 
 
 SimpleSignal::SimpleSignal(bool dealloc){
@@ -126,11 +127,6 @@ SignalSender::getOwnRef() const {
   return numberToRef(m_blockNo, theFacade->ownId());
 }
 
-Uint32
-SignalSender::getAliveNode() const{
-  return theFacade->get_an_alive_node();
-}
-
 const ClusterMgr::Node & 
 SignalSender::getNodeInfo(Uint16 nodeId) const {
   return theFacade->theClusterMgr->getNodeInfo(nodeId);
@@ -141,6 +137,55 @@ SignalSender::getNoOfConnectedNodes() co
   return theFacade->theClusterMgr->getNoOfConnectedNodes();
 }
 
+
+void
+SignalSender::getNodes(NodeBitmask& mask,
+                       NodeInfo::NodeType type)
+{
+  mask.clear();
+  for(Uint32 i = 0; i < MAX_NODES; i++)
+  {
+    const ClusterMgr::Node& node= getNodeInfo(i);
+    if(!node.defined)
+      continue;
+    if(type == NodeInfo::INVALID || // INVALID -> add all nodes to mask
+       node.m_info.getType() == type)
+    {
+      mask.set(i);
+    }
+  }
+}
+
+
+NodeBitmask
+SignalSender::broadcastSignal(NodeBitmask mask,
+                              SimpleSignal& sig,
+                              Uint16 recBlock, Uint16 gsn,
+                              Uint32 len)
+{
+  sig.set(*this, TestOrd::TraceAPI, recBlock, gsn, len);
+
+  NodeBitmask result;
+  for(Uint32 i = 0; i < MAX_NODES; i++)
+  {
+    if(mask.get(i) && sendSignal(i, &sig) == SEND_OK)
+      result.set(i);
+  }
+  return result;
+}
+
+
+SendStatus
+SignalSender::sendSignal(Uint16 nodeId,
+                         SimpleSignal& sig,
+                         Uint16 recBlock, Uint16 gsn,
+                         Uint32 len)
+{
+  sig.set(*this, TestOrd::TraceAPI, recBlock, gsn, len);
+  return sendSignal(nodeId, &sig);
+}
+
+
 template<class T>
 SimpleSignal *
 SignalSender::waitFor(Uint32 timeOutMillis, T & t)

=== modified file 'storage/ndb/src/ndbapi/SignalSender.hpp'
--- a/storage/ndb/src/ndbapi/SignalSender.hpp	2008-09-17 13:23:21 +0000
+++ b/storage/ndb/src/ndbapi/SignalSender.hpp	2008-10-24 12:51:04 +0000
@@ -51,17 +51,28 @@ public:
   int unlock();
 
   Uint32 getOwnRef() const;
-  Uint32 getAliveNode() const;
   const ClusterMgr::Node &getNodeInfo(Uint16 nodeId) const;
   Uint32 getNoOfConnectedNodes() const;
 
+  /*
+    Return bitmask of all defined nodes of a certain type
+    returns all defined nodes by default.
+   */
+  void getNodes(NodeBitmask& mask,
+                NodeInfo::NodeType type = NodeInfo::INVALID);
+
   SendStatus sendSignal(Uint16 nodeId, const SimpleSignal *);
-  
+  SendStatus sendSignal(Uint16 nodeId, SimpleSignal& sig,
+                        Uint16 recBlock, Uint16 gsn, Uint32 len);
+  NodeBitmask broadcastSignal(NodeBitmask mask, SimpleSignal& sig,
+                              Uint16 recBlock, Uint16 gsn, Uint32 len);
+
   SimpleSignal * waitFor(Uint32 timeOutMillis = 0);
   SimpleSignal * waitFor(Uint16 nodeId, Uint32 timeOutMillis = 0);
   SimpleSignal * waitFor(Uint16 nodeId, Uint16 gsn, Uint32 timeOutMillis = 0);  
 
-  Uint32 get_an_alive_node() { return theFacade->get_an_alive_node(); }
+  Uint32 get_an_alive_node() const { return theFacade->get_an_alive_node(); }
+  Uint32 getAliveNode() const { return get_an_alive_node(); }
   bool get_node_alive(NodeId n) const { return theFacade->get_node_alive(n); }
 
 private:

=== modified file 'storage/ndb/src/ndbapi/TransporterFacade.cpp'
--- a/storage/ndb/src/ndbapi/TransporterFacade.cpp	2008-09-10 00:32:18 +0000
+++ b/storage/ndb/src/ndbapi/TransporterFacade.cpp	2008-10-27 09:19:44 +0000
@@ -312,9 +312,16 @@ TransporterFacade::deliver_signal(Signal
        break;
 
      case GSN_API_REGCONF:
+     {
        clusterMgr->execAPI_REGCONF(theData);
+
+       // Distribute signal to all threads/blocks
+       NdbApiSignal tSignal(* header);
+       tSignal.setDataPtr(theData);
+       for_each(&tSignal, ptr);
        break;
-     
+     }
+
      case GSN_API_REGREF:
        clusterMgr->execAPI_REGREF(theData);
        break;
@@ -386,6 +393,16 @@ TransporterFacade::deliver_signal(Signal
        
      }
      return;
+  } else if (tRecBlockNo >= MIN_API_FIXED_BLOCK_NO &&
+             tRecBlockNo <= MAX_API_FIXED_BLOCK_NO) {
+    Uint32 dynamic= m_fixed2dynamic[tRecBlockNo - MIN_API_FIXED_BLOCK_NO];
+    oe = m_threads.get(dynamic);
+    if (oe.m_object != 0 && oe.m_executeFunction != 0) {
+      NdbApiSignal tmpSignal(*header);
+      NdbApiSignal * tSignal = &tmpSignal;
+      tSignal->setDataPtr(theData);
+      (* oe.m_executeFunction) (oe.m_object, tSignal, ptr);
+    }//if   
   } else {
     ; // Ignore all other block numbers.
     if(header->theVerId_signalNumber != GSN_API_REGREQ) {
@@ -701,6 +718,9 @@ TransporterFacade::TransporterFacade(Glo
   m_batch_size= DEF_BATCH_SIZE;
   m_max_trans_id = 0;
 
+  for (int i = 0; i < NO_API_FIXED_BLOCKS; i++)
+    m_fixed2dynamic[i]= RNIL;
+
   theClusterMgr = new ClusterMgr(* this);
 
 #ifdef API_TRACE
@@ -929,9 +949,20 @@ TransporterFacade::open(void* objRef, 
                         int blockNo)
 {
   DBUG_ENTER("TransporterFacade::open");
-  int r= m_threads.open(objRef, fun, statusFun, blockNo);
+  int r= m_threads.open(objRef, fun, statusFun);
   if (r < 0)
     DBUG_RETURN(r);
+
+  if (unlikely(blockNo != -1)){
+    // Using fixed block number, add fixed->dymamic mapping
+    Uint32 fixed_index= blockNo - MIN_API_FIXED_BLOCK_NO;
+
+    assert(blockNo >= MIN_API_FIXED_BLOCK_NO &&
+           fixed_index <= NO_API_FIXED_BLOCKS);
+
+    m_fixed2dynamic[fixed_index]= r;
+  }
+
 #if 1
   if (theOwnId > 0) {
     (*statusFun)(objRef, numberToRef(r, theOwnId), true, true);
@@ -1644,14 +1675,14 @@ TransporterFacade::get_an_alive_node()
 #endif
   NodeId i;
   for (i = theStartNodeId; i < MAX_NDB_NODES; i++) {
-    if (get_node_alive(i)){
+    if (getIsDbNode(i) && get_node_alive(i)){
       DBUG_PRINT("info", ("Node %d is alive", i));
       theStartNodeId = ((i + 1) % MAX_NDB_NODES);
       DBUG_RETURN(i);
     }
   }
   for (i = 1; i < theStartNodeId; i++) {
-    if (get_node_alive(i)){
+    if (getIsDbNode(i) && get_node_alive(i)){
       DBUG_PRINT("info", ("Node %d is alive", i));
       theStartNodeId = ((i + 1) % MAX_NDB_NODES);
       DBUG_RETURN(i);
@@ -1686,8 +1717,7 @@ TransporterFacade::ThreadData::expand(Ui
 int
 TransporterFacade::ThreadData::open(void* objRef, 
 				    ExecuteFunction fun, 
-				    NodeStatusFunction fun2,
-                                    int blockNo)
+				    NodeStatusFunction fun2)
 {
   Uint32 nextFree = m_firstFree;
 
@@ -1695,41 +1725,16 @@ TransporterFacade::ThreadData::open(void
     return -1;
   }
 
-  Object_Execute oe = { objRef , fun };
-
-  if (unlikely(blockNo >= 0)) {
-    // Open block with fixed number
-    Uint32 index= numberToIndex(blockNo);
-
-    if(index > m_statusNext.size()){
-      expand(index - m_statusNext.size());
-    }
-
-    m_use_cnt++;
-
-    // Single linked free list, relink the previous one that points to this
-    for(Uint32 i = 0; i < m_statusNext.size(); i++){
-      if (m_statusNext[i] == index){
-        m_statusNext[i]= m_statusNext[index];
-        break;
-      }
-    }
-
-    m_statusNext[index] = INACTIVE;
-    m_objectExecute[index] = oe;
-    m_statusFunction[index] = fun2;
-
-    return indexToNumber(index);
-  }
-
   if(nextFree == END_OF_LIST){
     expand(10);
     nextFree = m_firstFree;
   }
-  
+
   m_use_cnt++;
   m_firstFree = m_statusNext[nextFree];
 
+  Object_Execute oe = { objRef , fun };
+
   m_statusNext[nextFree] = INACTIVE;
   m_objectExecute[nextFree] = oe;
   m_statusFunction[nextFree] = fun2;
@@ -1950,6 +1955,18 @@ SignalSender::sendSignal(Uint16 nodeId, 
     signalLogger.flushSignalLog();
   }
 #endif
+
+  if (nodeId == theFacade->ownId())
+  {
+    SignalHeader tmp= s->header;
+    tmp.theSendersBlockRef = getOwnRef();
+    theFacade->deliver_signal(&tmp,
+                              1, // JBB
+                              (Uint32*)&s->theData[0],
+                              (LinearSectionPtr*)&s->ptr[0]);
+    return SEND_OK;
+  }
+
   assert(getNodeInfo(nodeId).m_api_reg_conf == true ||
          s->readSignalNumber() == GSN_API_REGREQ);
   

=== modified file 'storage/ndb/src/ndbapi/TransporterFacade.hpp'
--- a/storage/ndb/src/ndbapi/TransporterFacade.hpp	2008-08-26 14:05:01 +0000
+++ b/storage/ndb/src/ndbapi/TransporterFacade.hpp	2008-10-21 12:41:59 +0000
@@ -283,7 +283,7 @@ private:
     Vector<Object_Execute> m_objectExecute;
     Vector<NodeStatusFunction> m_statusFunction;
     
-    int open(void* objRef, ExecuteFunction, NodeStatusFunction, int);
+    int open(void* objRef, ExecuteFunction, NodeStatusFunction);
     int close(int number);
     void expand(Uint32 size);
 
@@ -303,7 +303,8 @@ private:
       return (m_statusNext[index] & (1 << 16)) != 0;
     }
   } m_threads;
-  
+
+  Uint32 m_fixed2dynamic[NO_API_FIXED_BLOCKS];
   Uint32 m_max_trans_id;
   Uint32 m_fragmented_signal_id;
 

=== modified file 'storage/ndb/test/run-test/Makefile.am'
--- a/storage/ndb/test/run-test/Makefile.am	2008-08-28 12:23:34 +0000
+++ b/storage/ndb/test/run-test/Makefile.am	2008-10-21 12:41:59 +0000
@@ -42,7 +42,6 @@ LDADD_LOC = $(top_builddir)/storage/ndb/
 atrt_CXXFLAGS = -I$(top_srcdir)/ndb/src/mgmapi \
                       -I$(top_srcdir)/ndb/src/mgmsrv \
                       -I$(top_srcdir)/ndb/include/mgmcommon \
-                      -DMYSQLCLUSTERDIR="\"\"" \
                  -DDEFAULT_PREFIX="\"$(prefix)\""
 
 atrt_LDFLAGS = -static @ndb_bin_am_ldflags@

Thread
bzr commit into mysql-5.1 branch (msvensson:3018) WL#4350Magnus Svensson27 Oct