List:Commits« Previous MessageNext Message »
From:jonas oreland Date:July 4 2011 8:39am
Subject:bzr push into mysql-5.5-cluster branch (jonas.oreland:3415 to 3418)
View as plain text  
 3418 jonas oreland	2011-07-04 [merge]
      ndb - merge 70-spj into 55

    modified:
      sql/ha_ndbcluster.cc
      sql/ha_ndbcluster.h
      sql/ha_ndbcluster_push.cc
      sql/ha_ndbcluster_push.h
 3417 jonas oreland	2011-07-04 [merge]
      ndb - merge 71 to 55

    added:
      storage/ndb/include/kernel/signaldata/GetConfig.hpp
      storage/ndb/src/common/debugger/signaldata/GetConfig.cpp
    modified:
      mysql-test/suite/ndb/r/ndb_config.result
      mysql-test/suite/ndb/t/ndb_config.test
      storage/ndb/include/kernel/GlobalSignalNumbers.h
      storage/ndb/include/kernel/signaldata/SignalData.hpp
      storage/ndb/include/mgmapi/mgmapi.h
      storage/ndb/include/ndb_version.h.in
      storage/ndb/src/common/debugger/signaldata/CMakeLists.txt
      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/blocks/cmvmi/Cmvmi.cpp
      storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.hpp
      storage/ndb/src/kernel/vm/Configuration.cpp
      storage/ndb/src/kernel/vm/Configuration.hpp
      storage/ndb/src/mgmapi/mgmapi.cpp
      storage/ndb/src/mgmapi/mgmapi_internal.h
      storage/ndb/src/mgmsrv/Defragger.hpp
      storage/ndb/src/mgmsrv/MgmtSrvr.cpp
      storage/ndb/src/mgmsrv/MgmtSrvr.hpp
      storage/ndb/src/mgmsrv/Services.cpp
      storage/ndb/src/ndbjtie/jtie/jtie_tconv_idcache_impl.hpp
      storage/ndb/src/ndbjtie/jtie/jtie_tconv_object.hpp
      storage/ndb/src/ndbjtie/jtie/jtie_tconv_object_impl.hpp
      storage/ndb/src/ndbjtie/jtie/jtie_tconv_ptrbybb_impl.hpp
      storage/ndb/test/ndbapi/testMgm.cpp
      storage/ndb/test/src/NDBT_Find.cpp
      storage/ndb/tools/ndb_config.cpp
 3416 jonas oreland	2011-07-04
      ndb - another 5.5 valgrind suppression ("same" as previous...)

    modified:
      mysql-test/valgrind.supp
 3415 jonas oreland	2011-07-01
      ndb - compiler warning: unused value

    modified:
      sql/ha_ndbcluster.cc
=== modified file 'mysql-test/suite/ndb/r/ndb_config.result'
--- a/mysql-test/suite/ndb/r/ndb_config.result	2011-07-01 09:20:02 +0000
+++ b/mysql-test/suite/ndb/r/ndb_config.result	2011-07-01 17:53:53 +0000
@@ -39,3 +39,5 @@ tcp,3,4,55,3 tcp,3,5,55,3 tcp,3,6,55,3 t
 2,37-48 1,1-2
 == 19 == bug12712109
 10485760 10485760 10485760 10485760 10485760
+1
+1

=== modified file 'mysql-test/suite/ndb/t/ndb_config.test'
--- a/mysql-test/suite/ndb/t/ndb_config.test	2011-07-01 09:16:46 +0000
+++ b/mysql-test/suite/ndb/t/ndb_config.test	2011-07-01 17:15:00 +0000
@@ -64,3 +64,8 @@ echo == 18 == bug56185;
 echo == 19 == bug12712109;
 --exec $NDB_CONFIG --config-file=$MYSQL_TEST_DIR/suite/ndb/bug12712109.ini --query=OverloadLimit --connections 2>&1
 
+# Read config generation number from nodes
+# From management server
+--exec $NDB_CONFIG --system --query=ConfigGenerationNumber
+# From a data node
+--exec $NDB_CONFIG --system --config-from-node=2 --query=ConfigGenerationNumber

=== modified file 'mysql-test/valgrind.supp'
--- a/mysql-test/valgrind.supp	2011-07-01 10:29:45 +0000
+++ b/mysql-test/valgrind.supp	2011-07-04 08:03:49 +0000
@@ -891,3 +891,15 @@
    fun:packfrm
 }
 
+{
+   NDB packfrm case 2
+   Memcheck:Cond
+   fun:longest_match
+   fun:deflate_slow
+   fun:deflate
+   fun:compress
+   fun:my_compress_alloc
+   fun:my_compress
+   fun:packfrm
+}
+

=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc	2011-07-01 11:53:46 +0000
+++ b/sql/ha_ndbcluster.cc	2011-07-04 08:38:03 +0000
@@ -893,30 +893,7 @@ SHOW_VAR ndb_status_index_stat_variables
 };
 
 #ifndef NO_PUSHED_JOIN
-
-/**
- * C++98 does not allow forward declarations of enum types. By using this 
- * class instead of using NdbQueryOperationDef::Type directly, 
- * ha_ndbcluster.h avoids including NdbQueryBuilder.h.
- */
-class NdbQueryOperationTypeWrapper
-{
-public:
-  /** Implcit conversion from NdbQueryOperationDef::Type.*/
-  NdbQueryOperationTypeWrapper(NdbQueryOperationDef::Type type)
-    :m_type(type)
-  {}
-
-  /** Implcit conversion to NdbQueryOperationDef::Type.*/
-  operator NdbQueryOperationDef::Type() const
-  { return m_type; }
-
-private:
-  const NdbQueryOperationDef::Type m_type;
-};
-
 static int ndbcluster_make_pushed_join(handlerton *, THD*,AQP::Join_plan*);
-
 #endif
 
 /*
@@ -3994,7 +3971,8 @@ ha_ndbcluster::pk_unique_index_read_key_
 
   uint i;
   Uint32 offset= 0;
-  NdbQueryParamValue paramValues[ndb_pushed_join::MAX_KEY_PART + ndb_pushed_join::MAX_REFERRED_FIELDS];
+  NdbQueryParamValue paramValues[ndb_pushed_join::MAX_KEY_PART];
+  DBUG_ASSERT(key_def->key_parts <= ndb_pushed_join::MAX_KEY_PART);
 
   uint map[ndb_pushed_join::MAX_KEY_PART];
   ndbcluster_build_key_map(m_table, m_index[idx], &table->key_info[idx], map);
@@ -4018,11 +3996,8 @@ ha_ndbcluster::pk_unique_index_read_key_
     offset+= key_part->store_length;
   }
 
-  const int error= create_pushed_join(paramValues, key_def->key_parts);
-  if (unlikely(error))
-    DBUG_RETURN(error);
-
-  DBUG_RETURN(0);
+  const int ret= create_pushed_join(paramValues, key_def->key_parts);
+  DBUG_RETURN(ret);
 } // ha_ndbcluster::pk_unique_index_read_key_pushed
 
 
@@ -4157,8 +4132,7 @@ int ha_ndbcluster::ordered_index_scan(co
   if (check_if_pushable(NdbQueryOperationDef::OrderedIndexScan, active_index,
                         sorted))
   {
-    NdbQueryParamValue paramValues[ndb_pushed_join::MAX_REFERRED_FIELDS];
-    const int error= create_pushed_join(paramValues);
+    const int error= create_pushed_join();
     if (unlikely(error))
       DBUG_RETURN(error);
 
@@ -4350,8 +4324,7 @@ int ha_ndbcluster::full_table_scan(const
 
   if (check_if_pushable(NdbQueryOperationDef::TableScan))
   {
-    NdbQueryParamValue paramValues[ndb_pushed_join::MAX_REFERRED_FIELDS];
-    const int error= create_pushed_join(paramValues);
+    const int error= create_pushed_join();
     if (unlikely(error))
       DBUG_RETURN(error);
 
@@ -13524,8 +13497,7 @@ ha_ndbcluster::read_multi_range_first(KE
       {
         if (!m_active_query)
         {
-          NdbQueryParamValue paramValues[ndb_pushed_join::MAX_REFERRED_FIELDS];
-          const int error= create_pushed_join(paramValues);
+          const int error= create_pushed_join();
           if (unlikely(error))
             DBUG_RETURN(error);
 
@@ -14170,141 +14142,37 @@ ha_ndbcluster::maybe_pushable_join(const
  *
  * @param type This is the operation type that the server want to execute.
  * @param idx  Index used whenever relevant for operation type
- * @param rootSorted True if the root operation is an ordered index scan 
+ * @param needSorted True if the root operation is an ordered index scan 
  * with sorted results.
  * @return True if the operation may be pushed.
  */
 bool 
-ha_ndbcluster::check_if_pushable(const NdbQueryOperationTypeWrapper& type, 
-                                 uint idx, bool needSorted) const
+ha_ndbcluster::check_if_pushable(int type,  //NdbQueryOperationDef::Type, 
+                                 uint idx,  
+                                 bool needSorted) const
 {
-  if (m_pushed_join_operation != PUSHED_ROOT)
-  {
-    return FALSE;
-  }
-
-  const NdbQueryDef& queryDef= m_pushed_join_member->get_query_def();
-  const NdbQueryOperationDef* const root_operation= 
-    queryDef.getQueryOperation((uint)PUSHED_ROOT);
-
-  const NdbQueryOperationTypeWrapper& query_def_type=  
-    root_operation->getType();
-
   if (m_disable_pushed_join)
   {
     DBUG_PRINT("info", ("Push disabled (HA_EXTRA_KEYREAD)"));
-    return FALSE;
-  }
-
-  if (query_def_type != type)
-  {
-    DBUG_PRINT("info", 
-               ("Cannot execute push join. Root operation prepared as %s "
-                "not executable as %s w/ index %d",
-                NdbQueryOperationDef::getTypeName(query_def_type),
-                NdbQueryOperationDef::getTypeName(type), idx));
-    return FALSE;
-  }
-
-  const NdbDictionary::Index* const expected_index= root_operation->getIndex();
-
-  // Check that we still use the same index as when the query was prepared.
-  switch (type)
-  {
-  case NdbQueryOperationDef::PrimaryKeyAccess:
-    DBUG_ASSERT(idx==table->s->primary_key);
-    break;
-
-  case NdbQueryOperationDef::UniqueIndexAccess:
-    DBUG_ASSERT(idx<MAX_KEY);
-    //          DBUG_ASSERT(m_index[idx].unique_index == expected_index);
-    if (m_index[idx].unique_index != expected_index)
-    {
-      DBUG_PRINT("info", ("Actual index %s differs from expected index %s."
-                          "Therefore, join cannot be pushed.", 
-                          m_index[idx].unique_index->getName(),
-                          expected_index->getName()));
-      return FALSE;
-    }
-    break;
-
-  case NdbQueryOperationDef::TableScan:
-    DBUG_ASSERT (idx==0);
-    if (needSorted)
-    {
-      DBUG_PRINT("info", 
-                 ("TableScan access not not be provied as sorted result. " 
-                  "Therefore, join cannot be pushed."));
-      return FALSE;
-    }
-    break;
-
-  case NdbQueryOperationDef::OrderedIndexScan:
-    DBUG_ASSERT(idx<MAX_KEY);
-    //          DBUG_ASSERT(m_index[idx].index == expected_index);
-    if (m_index[idx].index != expected_index)
-    {
-      DBUG_PRINT("info", ("Actual index %s differs from expected index %s. "
-                          "Therefore, join cannot be pushed.", 
-                          m_index[idx].index->getName(),
-                          expected_index->getName()));
-      return FALSE;
-    }
-    if (needSorted && queryDef.getQueryType() == NdbQueryDef::MultiScanQuery)
-    {
-      DBUG_PRINT("info", 
-                 ("OrderedIndexScan with scan siblings " 
-                  "can not execute as pushed join."));
-      return FALSE;
-    }
-    break;
-
-  default:
-    DBUG_ASSERT(false);
-    break;
-  }
-
-  // There may be referrences to Field values from tables outside the scope of
-  // our pushed join which are supplied as paramValues().
-  // If any of these are NULL values, join can't be pushed
-  for (uint i= 0; i < m_pushed_join_member->get_field_referrences_count(); i++)
-  {
-    Field* field= m_pushed_join_member->get_field_ref(i);
-    if (field->is_real_null())
-    {
-      DBUG_PRINT("info", 
-                 ("paramValue is NULL, can not execute as pushed join"));
-      return FALSE;
-    }
+    return false;
   }
-
-  return TRUE;
+  return   m_pushed_join_operation == PUSHED_ROOT
+        && m_pushed_join_member    != NULL
+        && m_pushed_join_member->match_definition(
+                        type,
+                        (idx<MAX_KEY) ? &m_index[idx] : NULL,
+                        needSorted);
 }
 
 int
-ha_ndbcluster::create_pushed_join(NdbQueryParamValue* paramValues, uint paramOffs)
+ha_ndbcluster::create_pushed_join(const NdbQueryParamValue* keyFieldParams, uint paramCnt)
 {
   DBUG_ENTER("create_pushed_join");
-  DBUG_ASSERT(m_pushed_join_operation == PUSHED_ROOT);
-  DBUG_PRINT("info", 
-             ("executing chain of %d pushed joins."
-              " First table is %s, accessed as %s.", 
-              m_pushed_join_member->get_operation_count(),
-              m_pushed_join_member->get_table(0)->alias,
-              NdbQueryOperationDef::getTypeName(
-                m_pushed_join_member->get_query_def().getQueryOperation((uint)PUSHED_ROOT)->getType()))
-             );
-
-  // There may be referrences to Field values from tables outside the scope of
-  // our pushed join: These are expected to be supplied as paramValues()
-  for (uint i= 0; i < m_pushed_join_member->get_field_referrences_count(); i++)
-  {
-    Field* field= m_pushed_join_member->get_field_ref(i);
-    DBUG_ASSERT(!field->is_real_null());  // Checked by ::check_if_pushable()
-    paramValues[paramOffs+i]= NdbQueryParamValue(field->ptr, false);
-  }
+  DBUG_ASSERT(m_pushed_join_member && m_pushed_join_operation == PUSHED_ROOT);
+
+  NdbQuery* const query= 
+    m_pushed_join_member->make_query_instance(m_thd_ndb->trans, keyFieldParams, paramCnt);
 
-  NdbQuery* const query= m_thd_ndb->trans->createQuery(&m_pushed_join_member->get_query_def(), paramValues);
   if (unlikely(query==NULL))
     ERR_RETURN(m_thd_ndb->trans->getNdbError());
 
@@ -14436,7 +14304,7 @@ ha_ndbcluster::test_push_flag(enum ha_pu
       DBUG_RETURN(true);
     }
     const NdbQueryDef& query_def = m_pushed_join_member->get_query_def();
-    const NdbQueryOperationTypeWrapper& root_type=
+    const NdbQueryOperationDef::Type root_type=
       query_def.getQueryOperation((uint)PUSHED_ROOT)->getType();
 
     /**
@@ -14456,7 +14324,7 @@ ha_ndbcluster::test_push_flag(enum ha_pu
     {
       for (uint i= 1; i < query_def.getNoOfOperations(); i++)
       {
-        const NdbQueryOperationTypeWrapper& child_type=
+        const NdbQueryOperationDef::Type child_type=
           query_def.getQueryOperation(i)->getType();
         if (child_type == NdbQueryOperationDef::TableScan ||
             child_type == NdbQueryOperationDef::OrderedIndexScan)

=== modified file 'sql/ha_ndbcluster.h'
--- a/sql/ha_ndbcluster.h	2011-07-01 10:35:04 +0000
+++ b/sql/ha_ndbcluster.h	2011-07-04 08:38:03 +0000
@@ -517,11 +517,12 @@ private:
   bool has_null_in_unique_index(uint idx_no) const;
   bool check_index_fields_not_null(KEY *key_info);
 
-  bool check_if_pushable(const NdbQueryOperationTypeWrapper& type,
-                         uint idx= 0,
-			 bool rootSorted= false) const;
+  bool check_if_pushable(int type, //NdbQueryOperationDef::Type,
+                         uint idx= MAX_KEY,
+                         bool rootSorted= false) const;
   bool check_is_pushed() const;
-  int create_pushed_join(NdbQueryParamValue* paramValues, uint paramOffs= 0);
+  int create_pushed_join(const NdbQueryParamValue* keyFieldParams=NULL,
+                         uint paramCnt= 0);
 
   int set_up_partition_info(partition_info *part_info,
                             NdbDictionary::Table&) const;

=== modified file 'sql/ha_ndbcluster_push.cc'
--- a/sql/ha_ndbcluster_push.cc	2011-06-30 12:19:14 +0000
+++ b/sql/ha_ndbcluster_push.cc	2011-07-04 08:38:03 +0000
@@ -41,6 +41,7 @@
 #include <ndbapi/NdbApi.hpp>
 #include <ndbapi/NdbInterpretedCode.hpp>
 #include "../storage/ndb/src/ndbapi/NdbQueryBuilder.hpp"
+#include "../storage/ndb/src/ndbapi/NdbQueryOperation.hpp"
 
 #include <ndb_version.h>
 
@@ -161,6 +162,153 @@ ndb_pushed_join::~ndb_pushed_join()
     m_query_def->destroy();
 }
 
+bool ndb_pushed_join::match_definition(
+                      int type, //NdbQueryOperationDef::Type, 
+                      const NDB_INDEX_DATA* idx,
+                      bool needSorted) const
+{
+  const NdbQueryOperationDef* const root_operation= 
+    m_query_def->getQueryOperation((uint)0);
+  const NdbQueryOperationDef::Type def_type=  
+    root_operation->getType();
+
+  if (def_type != type)
+  {
+    DBUG_PRINT("info", 
+               ("Cannot execute push join. Root operation prepared as %s "
+                "not executable as %s",
+                NdbQueryOperationDef::getTypeName(def_type),
+                NdbQueryOperationDef::getTypeName((NdbQueryOperationDef::Type)type)));
+    return FALSE;
+  }
+  const NdbDictionary::Index* const expected_index= root_operation->getIndex();
+
+  // Check that we still use the same index as when the query was prepared.
+  switch (def_type)
+  {
+  case NdbQueryOperationDef::PrimaryKeyAccess:
+    DBUG_ASSERT(idx!=NULL);
+    DBUG_ASSERT(idx->unique_index == expected_index);
+    break;
+
+  case NdbQueryOperationDef::UniqueIndexAccess:
+    DBUG_ASSERT(idx!=NULL);
+    // DBUG_ASSERT(idx->unique_index == expected_index);
+    if (idx->unique_index != expected_index)
+    {
+      DBUG_PRINT("info", ("Actual index %s differs from expected index %s."
+                          "Therefore, join cannot be pushed.", 
+                          idx->unique_index->getName(),
+                          expected_index->getName()));
+      return FALSE;
+    }
+    break;
+
+  case NdbQueryOperationDef::TableScan:
+    DBUG_ASSERT (idx==NULL && expected_index==NULL);
+    if (needSorted)
+    {
+      DBUG_PRINT("info", 
+                 ("TableScan access can not be provied as sorted result. " 
+                  "Therefore, join cannot be pushed."));
+      return FALSE;
+    }
+    break;
+
+  case NdbQueryOperationDef::OrderedIndexScan:
+    DBUG_ASSERT(idx!=NULL);
+    // DBUG_ASSERT(idx->index == expected_index);
+    if (idx->index != expected_index)
+    {
+      DBUG_PRINT("info", ("Actual index %s differs from expected index %s. "
+                          "Therefore, join cannot be pushed.", 
+                          idx->index->getName(),
+                          expected_index->getName()));
+      return FALSE;
+    }
+    if (needSorted && m_query_def->getQueryType() == NdbQueryDef::MultiScanQuery)
+    {
+      DBUG_PRINT("info", 
+                 ("OrderedIndexScan with scan siblings " 
+                  "can not execute as pushed join."));
+      return FALSE;
+    }
+    break;
+
+  default:
+    DBUG_ASSERT(false);
+    break;
+  }
+
+  /**
+   * There may be referrences to Field values from tables outside the scope of
+   * our pushed join which are supplied as paramValues().
+   * If any of these are NULL values, join can't be pushed.
+   */
+  for (uint i= 0; i < get_field_referrences_count(); i++)
+  {
+    Field* field= m_referred_fields[i];
+    if (field->is_real_null())
+    {
+      DBUG_PRINT("info", 
+                 ("paramValue is NULL, can not execute as pushed join"));
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+NdbQuery* ndb_pushed_join::make_query_instance(
+                       NdbTransaction* trans,
+                       const NdbQueryParamValue* keyFieldParams,
+                       uint paramCnt) const
+{
+  DBUG_ENTER("make_query_instance");
+  DBUG_PRINT("info", 
+             ("executing chain of %d pushed joins."
+              " First table is %s, accessed as %s.", 
+              get_operation_count(),
+              get_table(0)->alias,
+              NdbQueryOperationDef::getTypeName(
+                m_query_def->getQueryOperation((uint)0)->getType())
+             ));
+
+  const NdbQueryParamValue* paramValues = keyFieldParams;
+
+  /**
+   * There may be referrences to Field values from tables outside the scope of
+   * our pushed join: These are expected to be supplied as paramValues()
+   * after the keyFieldParams[]. 
+   */
+  uint outer_fields= get_field_referrences_count();
+  if (unlikely(outer_fields > 0))
+  {
+    uint size= sizeof(NdbQueryParamValue) * (paramCnt+outer_fields);
+    NdbQueryParamValue* extendedParams = reinterpret_cast<NdbQueryParamValue*>(alloca(size));
+    // Copy specified keyFieldParams[] first
+    for (uint i= 0; i < paramCnt; i++)
+    {
+      extendedParams[i]= keyFieldParams[i];
+    }
+
+    // There may be referrences to Field values from tables outside the scope of
+    // our pushed join: These are expected to be supplied as paramValues()
+    for (uint i= 0; i < outer_fields; i++)
+    {
+      Field* field= m_referred_fields[i];
+      DBUG_ASSERT(!field->is_real_null());  // Checked by ::check_if_pushable()
+      extendedParams[paramCnt+i]= NdbQueryParamValue(field->ptr, false);
+    }
+    paramValues= extendedParams;
+  }
+
+  NdbQuery* query= trans->createQuery(&get_query_def(), paramValues);
+  DBUG_RETURN(query);
+}
+
+/////////////////////////////////////////
+
 ndb_pushed_builder_ctx::ndb_pushed_builder_ctx(const AQP::Join_plan& plan)
 :
   m_plan(plan),

=== modified file 'sql/ha_ndbcluster_push.h'
--- a/sql/ha_ndbcluster_push.h	2011-06-23 06:59:40 +0000
+++ b/sql/ha_ndbcluster_push.h	2011-07-04 08:38:03 +0000
@@ -21,6 +21,7 @@
 
 #include "sql_bitmap.h"
 
+class NdbTransaction;
 class NdbQueryBuilder;
 class NdbQueryOperand;
 class NdbQueryOperationDef;
@@ -96,6 +97,20 @@ public:
   
   ~ndb_pushed_join(); 
 
+  /**
+   * Check that this prepared pushed query matches the type
+   * of operation specified by the arguments.
+   */
+  bool match_definition(int type, //NdbQueryOperationDef::Type, 
+                        const NDB_INDEX_DATA* idx,
+                        bool needSorted) const;
+
+  /** Create an executable instance of this defined query. */
+  NdbQuery* make_query_instance(
+                        NdbTransaction* trans,
+                        const NdbQueryParamValue* keyFieldParams,
+                        uint paramCnt) const;
+
   /** Get the number of pushed table access operations.*/
   uint get_operation_count() const
   { return m_operation_count; }
@@ -108,14 +123,6 @@ public:
   uint get_field_referrences_count() const
   { return m_field_count; }
 
-  /** Get the no'th referred field of table access operations that executes
-   * prior to the pushed join.*/
-  Field* get_field_ref(uint no) const
-  { 
-    DBUG_ASSERT(no < m_field_count);
-    return m_referred_fields[no]; 
-  }
-
   const NdbQueryDef& get_query_def() const
   { return *m_query_def; }
 

=== modified file 'storage/ndb/include/kernel/GlobalSignalNumbers.h'
--- a/storage/ndb/include/kernel/GlobalSignalNumbers.h	2011-05-19 09:16:32 +0000
+++ b/storage/ndb/include/kernel/GlobalSignalNumbers.h	2011-07-01 17:15:00 +0000
@@ -111,9 +111,10 @@ extern const GlobalSignalNumber NO_OF_SI
 #define GSN_CONFIG_CHECK_REF            52
 #define GSN_CONFIG_CHECK_CONF           53
 
-/* 54 unused */
-/* 55 unused */
-/* 56 unused */
+#define GSN_GET_CONFIG_REQ        54
+#define GSN_GET_CONFIG_REF        55
+#define GSN_GET_CONFIG_CONF       56
+
 /* 57 unused */
 /* 58 unused */
 /* 59 unused */

=== added file 'storage/ndb/include/kernel/signaldata/GetConfig.hpp'
--- a/storage/ndb/include/kernel/signaldata/GetConfig.hpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/include/kernel/signaldata/GetConfig.hpp	2011-07-01 17:15:00 +0000
@@ -0,0 +1,75 @@
+/*
+   Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+*/
+
+#ifndef GET_CONFIG_HPP
+#define GET_CONFIG_HPP
+
+#include "SignalData.hpp"
+
+/**
+ * GetConfig - Get the node's current configuration
+ *
+ * Successfull return = GET_CONFIG_CONF -  a long signal
+ */
+class GetConfigReq {
+  /**
+   * Sender(s) / Reciver(s)
+   */
+  // Blocks
+  friend class Cmvmi;
+  friend class MgmtSrvr;
+  friend bool printGET_CONFIG_REQ(FILE *, const Uint32 *, Uint32, Uint16);
+
+  STATIC_CONST( SignalLength = 2 );
+
+  Uint32 nodeId; // Node id of the receiver node
+  Uint32 senderRef;
+};
+
+class GetConfigRef {
+  /**
+   * Sender/Receiver
+   */
+  friend class Cmvmi;
+  friend class MgmtSrvr;
+  friend bool printGET_CONFIG_REF(FILE *, const Uint32 *, Uint32, Uint16);
+
+  STATIC_CONST( SignalLength = 1 );
+
+  Uint32 error;
+
+  enum ErrorCode {
+    WrongSender = 1,
+    WrongNodeId = 2,
+    NoConfig = 3
+  };
+};
+
+class GetConfigConf {
+  /**
+   * Sender(s) / Reciver(s)
+   */
+  // Blocks
+  friend class Cmvmi;
+  friend class MgmtSrvr;
+  friend bool printGET_CONFIG_CONF(FILE *, const Uint32 *, Uint32, Uint16);
+
+  STATIC_CONST( SignalLength = 1 );
+
+  Uint32 configLength; // config blob size
+};
+#endif

=== modified file 'storage/ndb/include/kernel/signaldata/SignalData.hpp'
--- a/storage/ndb/include/kernel/signaldata/SignalData.hpp	2011-06-07 12:19:47 +0000
+++ b/storage/ndb/include/kernel/signaldata/SignalData.hpp	2011-07-04 08:38:03 +0000
@@ -317,4 +317,8 @@ GSN_PRINT_SIGNATURE(printINDEX_STAT_IMPL
 GSN_PRINT_SIGNATURE(printINDEX_STAT_IMPL_REF);
 GSN_PRINT_SIGNATURE(printINDEX_STAT_REP);
 
+GSN_PRINT_SIGNATURE(printGET_CONFIG_REQ);
+GSN_PRINT_SIGNATURE(printGET_CONFIG_REF);
+GSN_PRINT_SIGNATURE(printGET_CONFIG_CONF);
+
 #endif

=== modified file 'storage/ndb/include/mgmapi/mgmapi.h'
--- a/storage/ndb/include/mgmapi/mgmapi.h	2011-06-21 13:10:37 +0000
+++ b/storage/ndb/include/mgmapi/mgmapi.h	2011-07-01 17:15:00 +0000
@@ -710,6 +710,18 @@ extern "C" {
 			 int num_args,
 			 struct ndb_mgm_reply* reply);
 
+  /**
+   * Get the current configuration from a node.
+   *
+   * @param handle the NDB management handle.
+   * @param nodeId of the node for which the configuration is requested.
+   * @return the current configuration from the requested node.
+   */
+  struct ndb_mgm_configuration *
+  ndb_mgm_get_configuration_from_node(NdbMgmHandle handle,
+                                      int nodeid);
+
+
   /** @} *********************************************************************/
   /**
    * @name Functions: Start/stop nodes

=== modified file 'storage/ndb/include/ndb_version.h.in'
--- a/storage/ndb/include/ndb_version.h.in	2011-06-23 06:59:40 +0000
+++ b/storage/ndb/include/ndb_version.h.in	2011-07-04 08:38:03 +0000
@@ -676,4 +676,21 @@ ndb_refresh_tuple(Uint32 x)
   }
 }
 
+#define NDBD_GET_CONFIG_SUPPORT_70 NDB_MAKE_VERSION(7,0,27)
+#define NDBD_GET_CONFIG_SUPPORT_71 NDB_MAKE_VERSION(7,1,16)
+
+static
+inline
+int
+ndbd_get_config_supported(Uint32 x)
+{
+  const Uint32 major = (x >> 16) & 0xFF;
+  const Uint32 minor = (x >>  8) & 0xFF;
+
+  if (major == 7 && minor == 0)
+    return x >= NDBD_GET_CONFIG_SUPPORT_70;
+
+  return x >= NDBD_GET_CONFIG_SUPPORT_71;
+}
+
 #endif

=== modified file 'storage/ndb/src/common/debugger/signaldata/CMakeLists.txt'
--- a/storage/ndb/src/common/debugger/signaldata/CMakeLists.txt	2011-06-21 13:58:00 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/CMakeLists.txt	2011-07-01 17:15:00 +0000
@@ -45,5 +45,5 @@ ADD_CONVENIENCE_LIBRARY(ndbsignaldata
         ScanFrag.cpp ApiVersion.cpp
         LocalRouteOrd.cpp
 	DbinfoScan.cpp NodePing.cpp
-	IndexStatSignal.cpp)
+	IndexStatSignal.cpp GetConfig.cpp)
 

=== added file 'storage/ndb/src/common/debugger/signaldata/GetConfig.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/GetConfig.cpp	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/GetConfig.cpp	2011-07-01 17:15:00 +0000
@@ -0,0 +1,48 @@
+/*
+   Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+*/
+
+#include <signaldata/GetConfig.hpp>
+
+bool
+printGET_CONFIG_REQ(FILE * output, const Uint32 * theData,
+                   Uint32 len, Uint16 receiverBlockNo)
+{
+  const GetConfigReq* sig = (const GetConfigReq*)theData;
+  fprintf(output, " nodeId : %u senderRef : %x\n",
+          sig->nodeId,
+          sig->senderRef);
+  return true;
+}
+
+bool
+printGET_CONFIG_REF(FILE * output, const Uint32 * theData,
+                   Uint32 len, Uint16 receiverBlockNo) {
+  const GetConfigRef* sig = (const GetConfigRef*)theData;
+  fprintf(output, " error : %u\n",
+          sig->error);
+  return true;
+}
+
+
+bool
+printGET_CONFIG_CONF(FILE * output, const Uint32 * theData,
+                   Uint32 len, Uint16 receiverBlockNo) {
+  const GetConfigConf* sig = (const GetConfigConf*)theData;
+  fprintf(output, " Config size : %u\n",
+          sig->configLength);
+  return true;
+}

=== modified file 'storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp	2011-06-07 12:19:47 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp	2011-07-04 08:38:03 +0000
@@ -268,6 +268,10 @@ SignalDataPrintFunctions[] = {
   ,{ GSN_INDEX_STAT_IMPL_REF, printINDEX_STAT_IMPL_REF }
   ,{ GSN_INDEX_STAT_REP, printINDEX_STAT_REP }
 
+  ,{ GSN_GET_CONFIG_REQ, printGET_CONFIG_REQ }
+  ,{ GSN_GET_CONFIG_REF, printGET_CONFIG_REF }
+  ,{ GSN_GET_CONFIG_CONF, printGET_CONFIG_CONF }
+
   ,{ 0, 0 }
 };
 

=== modified file 'storage/ndb/src/common/debugger/signaldata/SignalNames.cpp'
--- a/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp	2011-05-19 09:16:32 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/SignalNames.cpp	2011-07-01 17:15:00 +0000
@@ -771,5 +771,9 @@ const GsnName SignalNames [] = {
   ,{ GSN_INDEX_STAT_IMPL_CONF, "INDEX_STAT_IMPL_CONF" }
   ,{ GSN_INDEX_STAT_IMPL_REF, "INDEX_STAT_IMPL_REF" }
   ,{ GSN_INDEX_STAT_REP, "INDEX_STAT_REP" }
+
+  ,{ GSN_GET_CONFIG_REQ, "GET_CONFIG_REQ" }
+  ,{ GSN_GET_CONFIG_REF, "GET_CONFIG_REF" }
+  ,{ GSN_GET_CONFIG_CONF, "GET_CONFIG_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	2011-02-01 23:27:25 +0000
+++ b/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp	2011-07-01 17:15:00 +0000
@@ -170,10 +170,12 @@ ConfigRetriever::getConfig(Uint32 nodeid
 ndb_mgm_configuration *
 ConfigRetriever::getConfig(NdbMgmHandle mgm_handle)
 {
+  const int from_node = 0;
   ndb_mgm_configuration * conf =
     ndb_mgm_get_configuration2(mgm_handle,
                                m_version,
-                               m_node_type);
+                               m_node_type,
+                               from_node);
   if(conf == 0)
   {
     BaseString tmp(ndb_mgm_get_latest_error_msg(mgm_handle));

=== modified file 'storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp'
--- a/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp	2011-06-07 12:19:47 +0000
+++ b/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp	2011-07-04 08:38:03 +0000
@@ -44,6 +44,7 @@
 #include <signaldata/Sync.hpp>
 #include <signaldata/AllocMem.hpp>
 #include <signaldata/NodeStateSignalData.hpp>
+#include <signaldata/GetConfig.hpp>
 
 #include <EventLogger.hpp>
 #include <TimeQueue.hpp>
@@ -124,6 +125,8 @@ Cmvmi::Cmvmi(Block_context& ctx) :
   addRecSignal(GSN_ALLOC_MEM_REF, &Cmvmi::execALLOC_MEM_REF);
   addRecSignal(GSN_ALLOC_MEM_CONF, &Cmvmi::execALLOC_MEM_CONF);
 
+  addRecSignal(GSN_GET_CONFIG_REQ, &Cmvmi::execGET_CONFIG_REQ);
+
   subscriberPool.setSize(5);
   c_syncReqPool.setSize(5);
 
@@ -3171,3 +3174,57 @@ Cmvmi::execROUTE_ORD(Signal* signal)
   warningEvent("Unable to route GSN: %d from %x to %x",
 	       gsn, srcRef, dstRef);
 }
+
+
+void Cmvmi::execGET_CONFIG_REQ(Signal *signal)
+{
+  jamEntry();
+  const GetConfigReq* const req = (const GetConfigReq *)signal->getDataPtr();
+
+  Uint32 error = 0;
+  Uint32 retRef = req->senderRef; // mgm servers ref
+
+  if (retRef != signal->header.theSendersBlockRef)
+  {
+    error = GetConfigRef::WrongSender;
+  }
+
+  if (req->nodeId != getOwnNodeId())
+  {
+    error = GetConfigRef::WrongNodeId;
+  }
+
+  const Uint32 config_length = m_ctx.m_config.m_clusterConfigPacked.length();
+  if (config_length == 0)
+  {
+    error = GetConfigRef::NoConfig;
+  }
+
+  if (error)
+  {
+    warningEvent("execGET_CONFIG_REQ: failed %u", error);
+    GetConfigRef *ref = (GetConfigRef *)signal->getDataPtrSend();
+    ref->error = error;
+    sendSignal(retRef, GSN_GET_CONFIG_REF, signal,
+               GetConfigRef::SignalLength, JBB);
+    return;
+  }
+
+  const Uint32 nSections= 1;
+  LinearSectionPtr ptr[3];
+  ptr[0].p = (Uint32*)(m_ctx.m_config.m_clusterConfigPacked.get_data());
+  ptr[0].sz = (config_length + 3) / 4;
+
+  GetConfigConf *conf = (GetConfigConf *)signal->getDataPtrSend();
+
+  conf->configLength = config_length;
+
+  sendFragmentedSignal(retRef,
+                       GSN_GET_CONFIG_CONF,
+                       signal,
+                       GetConfigConf::SignalLength,
+                       JBB,
+                       ptr,
+                       nSections,
+                       TheEmptyCallback);
+}

=== modified file 'storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.hpp'
--- a/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.hpp	2011-02-01 23:27:25 +0000
+++ b/storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.hpp	2011-07-01 17:15:00 +0000
@@ -78,6 +78,8 @@ private:
   void execALLOC_MEM_REF(Signal*);
   void execALLOC_MEM_CONF(Signal*);
 
+  void execGET_CONFIG_REQ(Signal*);
+
   char theErrorMessage[256];
   void sendSTTORRY(Signal* signal);
 

=== modified file 'storage/ndb/src/kernel/vm/Configuration.cpp'
--- a/storage/ndb/src/kernel/vm/Configuration.cpp	2011-04-14 15:47:23 +0000
+++ b/storage/ndb/src/kernel/vm/Configuration.cpp	2011-07-04 08:31:41 +0000
@@ -32,6 +32,8 @@
 #include <mgmapi_configuration.hpp>
 #include <kernel_config_parameters.h>
 
+#include <util/ConfigValues.hpp>
+
 #include <ndbapi_limits.h>
 
 #include <EventLogger.hpp>
@@ -191,6 +193,9 @@ Configuration::fetch_configuration(const
   
   m_clusterConfig = p;
 
+  const ConfigValues * cfg = (ConfigValues*)m_clusterConfig;
+  cfg->pack(m_clusterConfigPacked);
+
   {
     Uint32 generation;
     ndb_mgm_configuration_iterator sys_iter(*p, CFG_SECTION_SYSTEM);

=== modified file 'storage/ndb/src/kernel/vm/Configuration.hpp'
--- a/storage/ndb/src/kernel/vm/Configuration.hpp	2011-04-12 11:59:36 +0000
+++ b/storage/ndb/src/kernel/vm/Configuration.hpp	2011-07-01 17:15:00 +0000
@@ -26,6 +26,7 @@
 #include <NdbMutex.h>
 #include <NdbThread.h>
 #include <util/SparseBitmask.hpp>
+#include <util/UtilBuffer.hpp>
 
 enum ThreadTypes
 {
@@ -147,6 +148,7 @@ private:
 
   ndb_mgm_configuration * m_ownConfig;
   ndb_mgm_configuration * m_clusterConfig;
+  UtilBuffer m_clusterConfigPacked;
 
   ndb_mgm_configuration_iterator * m_clusterConfigIter;
   ndb_mgm_configuration_iterator * m_ownConfigIterator;

=== modified file 'storage/ndb/src/mgmapi/mgmapi.cpp'
--- a/storage/ndb/src/mgmapi/mgmapi.cpp	2011-06-22 08:27:29 +0000
+++ b/storage/ndb/src/mgmapi/mgmapi.cpp	2011-07-04 08:31:41 +0000
@@ -2068,6 +2068,15 @@ ndb_mgm_dump_state(NdbMgmHandle handle,
 }
 
 extern "C"
+struct ndb_mgm_configuration *
+ndb_mgm_get_configuration_from_node(NdbMgmHandle handle,
+                                    int nodeid)
+{
+  return ndb_mgm_get_configuration2(handle, 0,
+                                    NDB_MGM_NODE_TYPE_UNKNOWN, nodeid);
+}
+
+extern "C"
 int 
 ndb_mgm_start_signallog(NdbMgmHandle handle, int nodeId, 
 			struct ndb_mgm_reply* reply) 
@@ -2466,7 +2475,7 @@ ndb_mgm_abort_backup(NdbMgmHandle handle
 extern "C"
 struct ndb_mgm_configuration *
 ndb_mgm_get_configuration2(NdbMgmHandle handle, unsigned int version,
-                           enum ndb_mgm_node_type nodetype)
+                           enum ndb_mgm_node_type nodetype, int from_node)
 {
   DBUG_ENTER("ndb_mgm_get_configuration2");
 
@@ -2487,6 +2496,23 @@ ndb_mgm_get_configuration2(NdbMgmHandle
     args.put("nodetype", nodetype);
   }
 
+  if (from_node != 0)
+  {
+    if (check_version_ge(handle->mgmd_version(),
+                         NDB_MAKE_VERSION(7,1,16),
+                         NDB_MAKE_VERSION(7,0,27),
+                         0))
+    {
+      args.put("from_node", from_node);
+    }
+    else
+    {
+      SET_ERROR(handle, NDB_MGM_GET_CONFIG_FAILED,
+                "The mgm server does not support getting config from_node");
+      DBUG_RETURN(0);
+    }
+  }
+
   const ParserRow<ParserDummy> reply[] = {
     MGM_CMD("get config reply", NULL, ""),
     MGM_ARG("result", String, Mandatory, "Error message"),    

=== modified file 'storage/ndb/src/mgmapi/mgmapi_internal.h'
--- a/storage/ndb/src/mgmapi/mgmapi_internal.h	2011-02-01 23:27:25 +0000
+++ b/storage/ndb/src/mgmapi/mgmapi_internal.h	2011-07-01 17:15:00 +0000
@@ -94,7 +94,8 @@ extern "C" {
   struct ndb_mgm_configuration *
   ndb_mgm_get_configuration2(NdbMgmHandle handle,
                              unsigned version,
-                             enum ndb_mgm_node_type nodetype);
+                             enum ndb_mgm_node_type nodetype,
+                             int from_node = 0);
 
 
 #ifdef __cplusplus

=== modified file 'storage/ndb/src/mgmsrv/Defragger.hpp'
--- a/storage/ndb/src/mgmsrv/Defragger.hpp	2011-02-02 00:40:07 +0000
+++ b/storage/ndb/src/mgmsrv/Defragger.hpp	2011-07-01 17:15:00 +0000
@@ -61,7 +61,14 @@ class Defragger {
 
 public:
   Defragger() {};
-  ~Defragger() {};
+  ~Defragger()
+  {
+    for (size_t i = m_buffers.size(); i > 0; --i)
+    {
+      delete m_buffers[i-1]; // free the memory of the fragment
+    }
+    // m_buffers will be freed by ~Vector
+  };
 
   /*
     return true when complete signal received
@@ -113,13 +120,12 @@ public:
     clear any unassembled signal buffers from node
   */
   void node_failed(NodeId nodeId) {
-    for (size_t i = 0; i < m_buffers.size(); i++)
+    for (size_t i = m_buffers.size(); i > 0; --i)
     {
-      DefragBuffer* dbuf = m_buffers[i];
-      if (dbuf->m_node_id == nodeId)
+      if (m_buffers[i-1]->m_node_id == nodeId)
       {
-        delete dbuf; // MASV ?
-        m_buffers.erase(i);
+        delete m_buffers[i]; // free the memory of the signal fragment
+	m_buffers.erase(i); // remove the reference from the vector.
       }
     }
   }

=== modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.cpp'
--- a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp	2011-06-27 07:00:44 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp	2011-07-04 08:25:28 +0000
@@ -21,6 +21,7 @@
 #include "ndb_mgmd_error.h"
 #include "Services.hpp"
 #include "ConfigManager.hpp"
+#include "Defragger.hpp"
 
 #include <NdbOut.hpp>
 #include <NdbApiSignal.hpp>
@@ -43,6 +44,7 @@
 #include <signaldata/CreateNodegroup.hpp>
 #include <signaldata/DropNodegroup.hpp>
 #include <signaldata/Sync.hpp>
+#include <signaldata/GetConfig.hpp>
 #include <NdbSleep.h>
 #include <portlib/NdbDir.hpp>
 #include <EventLogger.hpp>
@@ -737,6 +739,160 @@ MgmtSrvr::get_packed_config(ndb_mgm_node
   return m_config_manager->get_packed_config(node_type, &buf64, error);
 }
 
+bool
+MgmtSrvr::get_packed_config_from_node(NodeId nodeId,
+                            BaseString& buf64, BaseString& error)
+{
+  DBUG_ENTER("get_packed_config_from_node");
+
+  if (nodeId >= MAX_NODES_ID)
+  {
+    error.assfmt("Nodeid %d is greater than max nodeid %d. ",
+                 nodeId, MAX_NODES_ID);
+    DBUG_RETURN(false);
+  }
+
+  if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_UNKNOWN)
+  {
+    error.assfmt("Nodeid %d does not exist. ", nodeId);
+    DBUG_RETURN(false);
+  }
+
+  if (getNodeType(nodeId) != NDB_MGM_NODE_TYPE_NDB)
+  {
+    error.assfmt("Node %d is not an NDB node. ", nodeId);
+    DBUG_RETURN(false);
+  }
+
+  trp_node node = getNodeInfo(nodeId);
+
+  if (!node.m_alive)
+  {
+    error.assfmt("Data node %d is not alive. ", nodeId);
+    DBUG_RETURN(false);
+  }
+
+  const Uint32 version = node.m_info.m_version;
+
+  if (!ndbd_get_config_supported(version))
+  {
+    error.assfmt("Data node %d (version %d.%d.%d) does not support getting config. ",
+                 nodeId, ndbGetMajor(version),
+                 ndbGetMinor(version), ndbGetBuild(version));
+    DBUG_RETURN(false);
+  }
+
+  INIT_SIGNAL_SENDER(ss,nodeId);
+
+  SimpleSignal ssig;
+  GetConfigReq* req = CAST_PTR(GetConfigReq, ssig.getDataPtrSend());
+  req->senderRef = ss.getOwnRef();
+  req->nodeId = nodeId;
+
+  g_eventLogger->debug("Sending GET_CONFIG_REQ to %d", nodeId);
+
+  ssig.set(ss, TestOrd::TraceAPI, CMVMI, GSN_GET_CONFIG_REQ,
+           GetConfigReq::SignalLength);
+  if ((ss.sendSignal(nodeId, &ssig)) != SEND_OK)
+  {
+    DBUG_RETURN(false);
+  }
+
+  Defragger defragger;
+  while (true)
+  {
+    SimpleSignal *signal = ss.waitFor();
+    int gsn = signal->readSignalNumber();
+
+    switch (gsn)
+    {
+    case GSN_GET_CONFIG_CONF:
+    {
+      if (refToNode(signal->header.theSendersBlockRef) != nodeId)
+      {
+        error.assfmt("Internal Error: Reply from wrong node %d, expected from %d. ",
+                     refToNode(signal->header.theSendersBlockRef),
+                     nodeId);
+        DBUG_RETURN(false);
+      }
+
+      const GetConfigConf * const conf =
+	CAST_CONSTPTR(GetConfigConf, signal->getDataPtr());
+
+      if (signal->header.m_noOfSections != 1)
+      {
+        error.assfmt("Internal Error: Wrong number of sections %d received, expected %d. ",
+                     signal->header.m_noOfSections, 1);
+        DBUG_RETURN(false);
+      }
+
+      if (defragger.defragment(signal))
+      {
+        ConfigValuesFactory cf;
+        require(cf.unpack(signal->ptr[0].p, conf->configLength));
+
+        Config received_config(cf.getConfigValues());
+        if (!received_config.pack64(buf64))
+        {
+          error.assign("Failed to pack64");
+          DBUG_RETURN(false);
+        }
+        DBUG_RETURN(true);
+      }
+      // wait until all fragments are received
+      continue;
+    }
+
+    case GSN_GET_CONFIG_REF:
+    {
+      if (refToNode(ssig.header.theSendersBlockRef) != nodeId)
+      {
+        error.assfmt("Internal Error: Reply from wrong node %d, expected from %d. ",
+                     refToNode(signal->header.theSendersBlockRef),
+                     nodeId);
+        DBUG_RETURN(false);
+      }
+      const GetConfigRef * const ref =
+	CAST_CONSTPTR(GetConfigRef, signal->getDataPtr());
+      error.assfmt("Error in retrieving config from node %d: Internal error: %d",
+                   nodeId, ref->error);
+
+      DBUG_RETURN(false);
+    }
+
+    case GSN_NF_COMPLETEREP:
+    {
+      const NFCompleteRep * rep = CAST_CONSTPTR(NFCompleteRep,
+                                                signal->getDataPtr());
+      if (rep->failedNodeId == nodeId)
+      {
+        error.assfmt("Node %d is not available", nodeId);
+        DBUG_RETURN(false);
+      }
+      continue;
+    }
+
+    case GSN_NODE_FAILREP:
+    {
+      // Wait until GSN_NODE_COMPLETEREP is received.
+      continue;
+    }
+
+    case GSN_API_REGCONF:
+    case GSN_TAKE_OVERTCCONF:
+    case GSN_CONNECT_REP:
+      // Ignore
+      continue;
+
+    default:
+      report_unknown_signal(signal);
+      DBUG_RETURN(false);
+    }
+  }
+  // Should never come here
+  require(false);
+  DBUG_RETURN(false);
+}
 
 MgmtSrvr::~MgmtSrvr()
 {
@@ -2803,6 +2959,7 @@ MgmtSrvr::trp_deliver_signal(const NdbAp
       Uint32 theData[25];
       EventReport repData;
     };
+    bzero(theData, sizeof(theData));
     EventReport * event = &repData;
     event->setEventType(NDB_LE_Disconnected);
     event->setNodeId(_ownNodeId);
@@ -3957,7 +4114,7 @@ MgmtSrvr::change_config(Config& new_conf
     case GSN_NF_COMPLETEREP:
     {
       NodeId nodeId = refToNode(signal->header.theSendersBlockRef);
-      msg.assign("Node %d failed uring configuration change", nodeId);
+      msg.assign("Node %d failed during configuration change", nodeId);
       return false;
       break;
     }

=== modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.hpp'
--- a/storage/ndb/src/mgmsrv/MgmtSrvr.hpp	2011-06-21 13:10:37 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.hpp	2011-07-01 17:15:00 +0000
@@ -488,6 +488,10 @@ public:
   bool get_packed_config(ndb_mgm_node_type nodetype,
                          BaseString& buf64, BaseString& error);
 
+  /* Get copy of configuration packed with base64 from node nodeid */
+  bool get_packed_config_from_node(NodeId nodeid,
+                         BaseString& buf64, BaseString& error);
+
   void print_config(const char* section_filter = NULL,
                     NodeId nodeid_filter = 0,
                     const char* param_filter = NULL,

=== modified file 'storage/ndb/src/mgmsrv/Services.cpp'
--- a/storage/ndb/src/mgmsrv/Services.cpp	2011-06-01 07:40:49 +0000
+++ b/storage/ndb/src/mgmsrv/Services.cpp	2011-07-01 17:15:00 +0000
@@ -126,6 +126,7 @@ ParserRow<MgmApiSession> commands[] = {
     MGM_ARG("version", Int, Mandatory, "Configuration version number"),
     MGM_ARG("node", Int, Optional, "Node ID"),
     MGM_ARG("nodetype", Int, Optional, "Type of requesting node"),
+    MGM_ARG("from_node", Int, Optional, "Node to get config from"),
 
   MGM_CMD("get nodeid", &MgmApiSession::get_nodeid, ""),
     MGM_ARG("version", Int, Mandatory, "Configuration version number"),
@@ -608,10 +609,12 @@ MgmApiSession::getConfig(Parser_t::Conte
                          const class Properties &args)
 {
   Uint32 nodetype = NDB_MGM_NODE_TYPE_UNKNOWN;
+  Uint32 from_node = 0;
 
   // Ignoring mandatory parameter "version"
   // Ignoring optional parameter "node"
   args.get("nodetype", &nodetype);
+  args.get("from_node", &from_node);
 
   SLEEP_ERROR_INSERTED(1);
   m_output->println("get config reply");
@@ -619,8 +622,14 @@ MgmApiSession::getConfig(Parser_t::Conte
   BaseString pack64, error;
 
   UtilBuffer packed;
-  if (!m_mgmsrv.get_packed_config((ndb_mgm_node_type)nodetype,
-                                  pack64, error))
+
+  bool success =
+   (from_node == 0 || from_node == m_mgmsrv.getOwnNodeId()) ?
+                m_mgmsrv.get_packed_config((ndb_mgm_node_type)nodetype,
+                                           pack64, error) :
+                m_mgmsrv.get_packed_config_from_node(from_node,
+                                                     pack64, error);
+  if (!success)
   {
     m_output->println("result: %s", error.c_str());
     m_output->print("\n");

=== modified file 'storage/ndb/src/ndbjtie/jtie/jtie_tconv_idcache_impl.hpp'
--- a/storage/ndb/src/ndbjtie/jtie/jtie_tconv_idcache_impl.hpp	2011-02-02 09:52:33 +0000
+++ b/storage/ndb/src/ndbjtie/jtie/jtie_tconv_idcache_impl.hpp	2011-07-02 10:09:08 +0000
@@ -54,7 +54,7 @@
 
 // ---------------------------------------------------------------------------
 
-// JNI helper functions
+// Local JNI helper functions
 
 template< typename T >
 inline T
@@ -108,30 +108,120 @@ jniGetMemberID< jfieldID >(JNIEnv * env,
 /**
  * Instantiates an info type describing a member of a Java class.
  */
-#define JTIE_INSTANTIATE_CLASS_MEMBER_INFO( T, CN, MN, MD )     \
-    const char * const T::class_name = CN;                      \
-    const char * const T::member_name = MN;                     \
-    const char * const T::member_descriptor = MD;               \
-    template struct MemberId< T >;                              \
+#define JTIE_INSTANTIATE_CLASS_MEMBER_INFO( T, CN, MN, MD )             \
+    const char * const T::class_name = CN;                              \
+    const char * const T::member_name = MN;                             \
+    const char * const T::member_descriptor = MD;                       \
+    template struct MemberId< T >;                                      \
     template struct MemberIdCache< T >;
 
-// XXX document these classes...
-
+/**
+ * Provides uniform access to the JNI Field/Method ID of a Java class member
+ * as described by the member info type 'C'.
+ *
+ * This base class does not cache the member ID and the class object, but
+ * it retrieves the member ID from JNI upon each access; different caching
+ * strategies are provided by derived classes.
+ *
+ * This class (and its derived classes) impose a strict usage pattern.
+ * For example, given definitions...
+ *
+ *    // Defines the field info type for MyClass.myField.
+ *    JTIE_DEFINE_FIELD_MEMBER_INFO(_MyClass_myField)
+ *
+ *    // Provides a (cached) access to field Id of MyClass.myField.
+ *    typedef JniMemberId< _MyClass_myField > MyClass_myField;
+ *
+ * any use of a member ID must be bracketed by getClass() and releaseRef():
+ *
+ *    // obtain a class reference
+ *    jclass cls = MyClass_myField::getClass(env);
+ *    if (cls == NULL) {
+ *        // exception pending
+ *    } else {
+ *        // get the field ID valid along with the class reference
+ *        jfieldID fid = MyClass_myField::getId(env, cls);
+ *        if (fid == NULL) {
+ *            // exception pending
+ *        } else {
+ *            // OK to access field using 'fid'
+ *        }
+ *        // allow for releasing the class reference
+ *        MyClass_myField::releaseRef(env, cls);
+ *    }
+ *
+ * Derived classes implement any caching underneath this usage pattern.
+ */
 template< typename C >
 struct MemberId {
     typedef typename C::memberID_t ID_t;
-    
-    // number of JNI Get<Field|Method>ID() invocations
+
+    // number of JNI Get<Field|Method>ID() invocations for statistics
     static unsigned long nIdLookUps;
 
+    /**
+     * Allows for storing a (global) class reference.
+     *
+     * Usually only called from getClass(), but enables "cache preloading"
+     * from a (native, static) function called at class initialization.
+     *
+     * Pre condition:
+     * - this thread has no pending JNI exception (!env->ExceptionCheck())
+     * - a valid local or global class reference: assert(cls != NULL)
+     */
     static void setClass(JNIEnv * env, jclass cls) {
+        assert(cls != NULL);
         (void)env; (void)cls;
     }
 
+    /**
+     * Returns a JNI Reference to the class declaring the member specified
+     * by info type 'C'.
+     *
+     * Depending upon the underlying caching strategy, a returned reference
+     * may be local or global, weak or strong; the scope of its use must be
+     * demarcated by releaseRef().
+     *
+     * Pre condition:
+     * - this thread has no pending JNI exception (!env->ExceptionCheck())
+     *
+     * Post condition:
+     * - return value is
+     *   NULL:
+     *     - this thread has a pending JNI exception (env->ExceptionCheck())
+     *   otherwise:
+     *     - this thread has no pending JNI exception (!env->ExceptionCheck())
+     *     - the returned reference is valid (at least) until releaseRef()
+     */
     static jclass getClass(JNIEnv * env) {
-        return env->FindClass(C::class_name);
+        assert(env->ExceptionCheck() == JNI_OK);
+        jclass cls = env->FindClass(C::class_name);
+        if (cls == NULL) { // break out for better diagnostics
+            assert(env->ExceptionCheck() != JNI_OK); // exception pending
+        } else {
+            assert(env->ExceptionCheck() == JNI_OK); // ok
+        }
+        return cls;
     }
 
+    /**
+     * Returns the JNI Field/Method ID of a Java class member.
+     *
+     * The member ID is only valid along with a class object obtained by
+     * getClass() and before releaseRef().
+     *
+     * Pre condition:
+     * - this thread has no pending JNI exception (!env->ExceptionCheck())
+     * - a valid class reference obtained by getClass(): assert(cls != NULL)
+     *
+     * Post condition:
+     * - return value is
+     *   NULL:
+     *     - this thread has a pending JNI exception (env->ExceptionCheck())
+     *   otherwise:
+     *     - this thread has no pending JNI exception (!env->ExceptionCheck())
+     *     - the returned member ID is valid (at least) until releaseRef()
+     */
     static ID_t getId(JNIEnv * env, jclass cls) {
         assert(cls != NULL);
         // multithreaded access ok, inaccurate if non-atomic increment
@@ -139,71 +229,104 @@ struct MemberId {
         return jniGetMemberID< ID_t >(env, cls,
                                       C::member_name, C::member_descriptor);
     }
-    
+
+    /**
+     * Allows for a class reference to be released along with any member IDs.
+     *
+     * Pre condition:
+     * - a valid class reference obtained by getClass(): assert(cls != NULL)
+     * - this thread may have a pending JNI exception (env->ExceptionCheck())
+     */
     static void releaseRef(JNIEnv * env, jclass cls) {
+        assert(cls != NULL);
         env->DeleteLocalRef(cls);
     }
 };
 
+/**
+ * Base class for caching of JNI Field/Method IDs.
+ */
 template< typename C >
 struct MemberIdCache : MemberId< C > {
     typedef typename C::memberID_t ID_t;
 
     static ID_t getId(JNIEnv * env, jclass cls) {
-        assert (cls != NULL);
+        assert(cls != NULL);
+        // the cached member id is only valid along with global class ref
+        assert(env->IsSameObject(gClassRef, NULL) == JNI_FALSE);
         (void)env; (void)cls;
         return mid;
     }
 
 protected:
+    // the cached global (weak or strong) class ref
     static jclass gClassRef;
+
+    // the cached member id (only valid along with global class ref)
     static ID_t mid;
 };
 
+/**
+ * Provides caching of JNI Field/Method IDs using weak class references,
+ * allowing classes to be unloaded when no longer used by Java code.
+ */
 template< typename C >
 struct MemberIdWeakCache : MemberIdCache< C > {
     typedef MemberId< C > A;
     typedef MemberIdCache< C > Base;
 
     static void setClass(JNIEnv * env, jclass cls) {
-        assert (cls != NULL);
+        assert(cls != NULL);
 
         // multithreaded access ok, sets same class/member object
-        Base::gClassRef = static_cast<jclass>(env->NewWeakGlobalRef(cls));
+        Base::gClassRef = static_cast< jclass >(env->NewWeakGlobalRef(cls));
         Base::mid = A::getId(env, cls);
     }
 
-    using Base::getId;
-    
+    using Base::getId; // use as inherited (some compiler wanted this)
+
     static jclass getClass(JNIEnv * env) {
-        jclass cls = static_cast<jclass>(env->NewLocalRef(Base::gClassRef));
+        // a weak global class ref may refer to a freed object at any time
+        //   (i.e.: env->IsSameObject(Base::gClassRef, NULL))
+        // unless we've obtained a strong (local or global) non-NULL class ref
+        jclass cls = static_cast< jclass >(env->NewLocalRef(Base::gClassRef));
         if (cls == NULL) {
+            // global class ref was NULL or referencing a freed object
             cls = A::getClass(env);
-            setClass(env, cls);
+            if (cls == NULL) {
+                // exception pending
+            } else {
+                setClass(env, cls);
+            }
         }
         return cls;
     }
-    
+
     static void releaseRef(JNIEnv * env, jclass cls) {
+        assert(cls != NULL);
         env->DeleteLocalRef(cls);
     }
 };
 
+/**
+ * Provides caching of JNI Field/Method IDs using strong class references,
+ * preventing classes from being unloaded even if no longer used by Java code.
+ */
 template< typename C >
 struct MemberIdStrongCache : MemberIdCache< C > {
     typedef MemberId< C > A;
     typedef MemberIdCache< C > Base;
-    
+
     static void setClass(JNIEnv * env, jclass cls) {
-        assert (cls != NULL);
+        assert(cls != NULL);
 
         // multithreaded access ok, sets same class/member object
-        Base::gClassRef = static_cast<jclass>(env->NewGlobalRef(cls));
+        Base::gClassRef = static_cast< jclass >(env->NewGlobalRef(cls));
         Base::mid = A::getId(env, cls);
     }
 
-    using Base::getId;
-    
+    using Base::getId; // use as inherited (some compiler wanted this)
+
     static jclass getClass(JNIEnv * env) {
         jclass cls = Base::gClassRef;
         if (cls == NULL) {
@@ -212,48 +335,61 @@ struct MemberIdStrongCache : MemberIdCac
         }
         return cls;
     }
-    
+
     static void releaseRef(JNIEnv * env, jclass cls) {
+        assert(cls != NULL);
+        (void)env; (void)cls;
     }
 };
 
+/**
+ * Provides caching of JNI Field/Method IDs using weak class references
+ * with preloading (at class initialization) -- VERY TRICKY, NOT SUPPORTED.
+ */
 template< typename C >
 struct MemberIdPreloadedWeakCache : MemberIdWeakCache< C > {
     typedef MemberIdWeakCache< C > Base;
-    
-    using Base::setClass;
 
-    using Base::getId;
-    
+    using Base::setClass; // use as inherited (some compiler wanted this)
+
+    using Base::getId; // use as inherited (some compiler wanted this)
+
     static jclass getClass(JNIEnv * env) {
+        // weak global class ref is assumed to be preloaded and valid
         jclass cls = Base::gClassRef;
-        assert (cls != NULL);
+        assert(env->IsSameObject(cls, NULL) == JNI_FALSE);
         return cls;
     }
-    
+
     static void releaseRef(JNIEnv * env, jclass cls) {
+        assert(cls != NULL);
+        (void)env; (void)cls;
     }
 };
 
+/**
+ * Provides caching of JNI Field/Method IDs using strong class references
+ * with preloading (at class initialization) -- VERY TRICKY, NOT SUPPORTED.
+ */
 template< typename C >
 struct MemberIdPreloadedStrongCache : MemberIdStrongCache< C > {
     typedef MemberIdStrongCache< C > Base;
-    
-    using Base::setClass;
 
-    using Base::getId;
-    
+    using Base::setClass; // use as inherited (some compiler wanted this)
+
+    using Base::getId; // use as inherited (some compiler wanted this)
+
     static jclass getClass(JNIEnv * env) {
+        // strong global class ref is assumed to be preloaded and valid
         jclass cls = Base::gClassRef;
-        assert (cls != NULL);
+        assert(env->IsSameObject(cls, NULL) == JNI_FALSE);
         return cls;
-    }    
+    }
 
-    using Base::releaseRef;
+    using Base::releaseRef; // use as inherited (some compiler wanted this)
 };
 
-// XXX test with multiple compilation units <-> jtie_lib.hpp
-
+// XXX static initialization <-> multiple compilation units <-> jtie_lib.hpp
 template< typename C > unsigned long MemberId< C >
     ::nIdLookUps = 0;
 
@@ -265,14 +401,22 @@ template< typename C > typename C::membe
 
 // XXX document
 
+/**
+ * The supported caching strategies for member IDs and class references.
+ */
 enum JniMemberIdCaching {
-    NO_CACHING,
-    WEAK_CACHING,
-    STRONG_CACHING,
-    WEAK_CACHING_PRELOAD,
-    STRONG_CACHING_PRELOAD
+    NO_CACHING
+    ,WEAK_CACHING
+    ,STRONG_CACHING
+#if 0 // preloaded caching very tricky, not supported at this time
+    ,WEAK_CACHING_PRELOAD
+    ,STRONG_CACHING_PRELOAD
+#endif // preloaded caching very tricky, not supported at this time
 };
 
+/**
+ * Generic class for member ID access with selection of caching strategy.
+ */
 template< JniMemberIdCaching M, typename C >
 struct JniMemberId;
 
@@ -288,6 +432,7 @@ template< typename C >
 struct JniMemberId< STRONG_CACHING, C >
     : MemberIdStrongCache< C > {};
 
+#if 0 // preloaded caching very tricky, not supported at this time
 template< typename C >
 struct JniMemberId< WEAK_CACHING_PRELOAD, C >
     : MemberIdPreloadedWeakCache< C > {};
@@ -295,6 +440,7 @@ struct JniMemberId< WEAK_CACHING_PRELOAD
 template< typename C >
 struct JniMemberId< STRONG_CACHING_PRELOAD, C >
     : MemberIdPreloadedStrongCache< C > {};
+#endif // preloaded caching very tricky, not supported at this time
 
 // ---------------------------------------------------------------------------
 

=== modified file 'storage/ndb/src/ndbjtie/jtie/jtie_tconv_object.hpp'
--- a/storage/ndb/src/ndbjtie/jtie/jtie_tconv_object.hpp	2011-02-02 09:52:33 +0000
+++ b/storage/ndb/src/ndbjtie/jtie/jtie_tconv_object.hpp	2011-07-02 10:09:08 +0000
@@ -44,6 +44,13 @@ struct _jtie_Object : _jobject {
 // XXX, document: type specifying an Object mapping with a class name
 
 // trait type wrapping named-parametrized Object mappings for specialization
+// XXX make use of
+//   JTIE_DEFINE_METHOD_MEMBER_INFO( _jtie_ObjectMapper< T > )
+// to replace
+//   static const char * const class_name;
+//   static const char * const member_name;
+//   static const char * const member_descriptor;
+//   typedef _jmethodID * memberID_t;
 template< typename J >
 struct _jtie_ObjectMapper : _jtie_Object {
     // the name of the Java peer class in the JVM format (i.e., '/'-separated)
@@ -55,11 +62,10 @@ struct _jtie_ObjectMapper : _jtie_Object
     typedef _jmethodID * memberID_t;
 };
 
-// XXX can/should these definitions be moves to _lib ?
-
+// XXX static initialization <-> multiple compilation units <-> jtie_lib.hpp
 template< typename J >
 const char * const _jtie_ObjectMapper< J >::class_name
-    = J::class_name;
+    = J::class_name; // XXX static initialization order dependency?
 
 template< typename J >
 const char * const _jtie_ObjectMapper< J >::member_name
@@ -214,6 +220,13 @@ const char * const _jtie_ObjectMapper< J
 #endif // XXX cleanup this unsupported mapping
 
 // XXX to document
+// XXX static initialization <-> multiple compilation units <-> jtie_lib.hpp
+// XXX replace
+//   template struct MemberId< _jtie_ObjectMapper< T > >;
+//   template struct MemberIdCache< _jtie_ObjectMapper< T > >;
+// with
+//   JTIE_INSTANTIATE_CLASS_MEMBER_INFO_X(_jtie_ObjectMapper< T >,
+//                                        JCN, "<init>", "()V")
 #define JTIE_INSTANTIATE_PEER_CLASS_MAPPING( T, JCN )           \
     const char * const T::class_name = JCN;                     \
     template struct _jtie_ObjectMapper< T >;                    \

=== modified file 'storage/ndb/src/ndbjtie/jtie/jtie_tconv_object_impl.hpp'
--- a/storage/ndb/src/ndbjtie/jtie/jtie_tconv_object_impl.hpp	2011-02-02 09:52:33 +0000
+++ b/storage/ndb/src/ndbjtie/jtie/jtie_tconv_object_impl.hpp	2011-07-02 10:09:08 +0000
@@ -40,14 +40,10 @@
 // Defines the field info type for Wrapper.cdelegate.
 JTIE_DEFINE_FIELD_MEMBER_INFO(_Wrapper_cdelegate)
 
-// XXX fix and test _PRELOAD caching
-
-// Provides a (cached) access to field Id  of Wrapper.cdelegate.
+// Provides a (cached) access to field Id of Wrapper.cdelegate.
 //typedef JniMemberId< NO_CACHING, _Wrapper_cdelegate > Wrapper_cdelegate;
 typedef JniMemberId< WEAK_CACHING, _Wrapper_cdelegate > Wrapper_cdelegate;
 //typedef JniMemberId< STRONG_CACHING, _Wrapper_cdelegate > Wrapper_cdelegate;
-//typedef JniMemberId< WEAK_CACHING_PRELOAD, _Wrapper_cdelegate > Wrapper_cdelegate;
-//typedef JniMemberId< STRONG_CACHING_PRELOAD, _Wrapper_cdelegate > Wrapper_cdelegate;
 
 // XXX consider changing
 //template< typename C > struct ObjectParam< _jtie_Object *, C * > {

=== modified file 'storage/ndb/src/ndbjtie/jtie/jtie_tconv_ptrbybb_impl.hpp'
--- a/storage/ndb/src/ndbjtie/jtie/jtie_tconv_ptrbybb_impl.hpp	2011-02-02 09:52:33 +0000
+++ b/storage/ndb/src/ndbjtie/jtie/jtie_tconv_ptrbybb_impl.hpp	2011-07-02 10:09:08 +0000
@@ -132,7 +132,7 @@ struct ByteBufferPtrParam {
                     } else {
                         // ok
                         s = 0;
-                        c = static_cast<C *>(a);
+                        c = static_cast< C * >(a);
                     }
                 }
             }
@@ -333,7 +333,7 @@ getBufferPosition(jtie_j_n_ByteBuffer jb
 inline void *
 getByteBufferAddress(jtie_j_n_ByteBuffer jbb, JNIEnv * env) {
     // get the internal buffer address of direct ByteBuffer
-    char * a = static_cast<char *>(env->GetDirectBufferAddress(jbb));
+    char * a = static_cast< char * >(env->GetDirectBufferAddress(jbb));
     if (a == NULL) {
 #ifndef JTIE_BYTEBUFFER_NO_ZERO_CAPACITY_MAPPING
         // check for direct ByteBuffer of zero-capacity

=== modified file 'storage/ndb/test/ndbapi/testMgm.cpp'
--- a/storage/ndb/test/ndbapi/testMgm.cpp	2011-02-22 08:40:01 +0000
+++ b/storage/ndb/test/ndbapi/testMgm.cpp	2011-07-01 17:15:00 +0000
@@ -23,6 +23,7 @@
 #include <InputStream.hpp>
 #include <signaldata/EventReport.hpp>
 #include <NdbRestarter.hpp>
+#include <random.h>
 
 /*
   Tests that only need the mgmd(s) started
@@ -714,6 +715,174 @@ int runGetConfigUntilStopped(NDBT_Contex
 }
 
 
+// Find a random node of a given type.
+
+static bool
+get_nodeid_of_type(NdbMgmd& mgmd, ndb_mgm_node_type type, int *nodeId)
+{
+  ndb_mgm_node_type
+    node_types[2] = { type,
+                      NDB_MGM_NODE_TYPE_UNKNOWN };
+
+  ndb_mgm_cluster_state *cs = ndb_mgm_get_status2(mgmd.handle(), node_types);
+  if (cs == NULL)
+  {
+    g_err << "ndb_mgm_get_status2 failed, error: "
+            << ndb_mgm_get_latest_error(mgmd.handle()) << " "
+            << ndb_mgm_get_latest_error_msg(mgmd.handle()) << endl;
+    return false;
+  }
+
+  int noOfNodes = cs->no_of_nodes;
+  int randomnode = myRandom48(noOfNodes);
+  ndb_mgm_node_state *ns = cs->node_states + randomnode;
+  assert(ns->node_type == (Uint32)type);
+  assert(ns->node_id);
+
+  *nodeId = ns->node_id;
+  g_info << "Got node id " << *nodeId << " of type " << type << endl;
+
+  free(cs);
+  return true;
+}
+
+
+// Ensure getting config from an illegal node fails.
+// Return true in that case.
+
+static bool
+get_config_from_illegal_node(NdbMgmd& mgmd, int nodeId)
+{
+  struct ndb_mgm_configuration* conf=
+      ndb_mgm_get_configuration_from_node(mgmd.handle(), nodeId);
+
+  // Get conf from an illegal node should fail.
+  if (ndb_mgm_get_latest_error(mgmd.handle()) != NDB_MGM_GET_CONFIG_FAILED)
+  {
+      g_err << "ndb_mgm_get_configuration from illegal node "
+            << nodeId << " not failed, error: "
+            << ndb_mgm_get_latest_error(mgmd.handle()) << " "
+            << ndb_mgm_get_latest_error_msg(mgmd.handle()) << endl;
+      return false;
+  }
+
+  if (conf)
+  {
+    // Should not get a conf from an illegal node.
+    g_err << "ndb_mgm_get_configuration from illegal node: "
+          << nodeId << ", error: "
+          << ndb_mgm_get_latest_error(mgmd.handle()) << " "
+          << ndb_mgm_get_latest_error_msg(mgmd.handle()) << endl;
+    free(conf);
+    return false;
+  }
+  return true;
+}
+
+
+// Check get_config from a non-existing node fails.
+
+static bool
+check_get_config_illegal_node(NdbMgmd& mgmd)
+{
+  // Find a node that does not exist
+  Config conf;
+  if (!mgmd.get_config(conf))
+    return false;
+
+  int nodeId = 0;
+  for(Uint32 i= 1; i < MAX_NODES; i++){
+    ConfigIter iter(&conf, CFG_SECTION_NODE);
+    if (iter.find(CFG_NODE_ID, i) != 0){
+      nodeId = i;
+      break;
+    }
+  }
+  if (nodeId == 0)
+    return true; // All nodes probably defined
+
+  return get_config_from_illegal_node(mgmd, nodeId);
+}
+
+
+
+// Check get_config from a non-NDB/MGM node type fails
+
+static bool
+check_get_config_wrong_type(NdbMgmd& mgmd)
+{
+  int nodeId = 0;
+
+  if (get_nodeid_of_type(mgmd, NDB_MGM_NODE_TYPE_API, &nodeId))
+  {
+    return get_config_from_illegal_node(mgmd, nodeId);
+  }
+  // No API nodes found.
+  return true;
+}
+
+/* Find management node or a random data node, and get config from it.
+ * Also ensure failure when getting config from
+ * an illegal node (a non-NDB/MGM type, nodeid not defined,
+ * or nodeid > MAX_NODES).
+ */
+int runGetConfigFromNode(NDBT_Context* ctx, NDBT_Step* step)
+{
+  NdbMgmd mgmd;
+  if (!mgmd.connect())
+    return NDBT_FAILED;
+
+  if (!check_get_config_wrong_type(mgmd) ||
+      !check_get_config_illegal_node(mgmd) ||
+      !get_config_from_illegal_node(mgmd, MAX_NODES + 2))
+  {
+    return NDBT_FAILED;
+  }
+
+  int loops= ctx->getNumLoops();
+  for (int l= 0; l < loops; l++)
+  {
+    /* Get config from a node of type:
+     * NDB_MGM_NODE_TYPE_NDB or NDB_MGM_NODE_TYPE_MGM
+     */
+    int myChoice = myRandom48(2);
+    ndb_mgm_node_type randomAllowedType = (myChoice) ?
+                                          NDB_MGM_NODE_TYPE_NDB :
+                                          NDB_MGM_NODE_TYPE_MGM;
+    int nodeId = 0;
+    if (get_nodeid_of_type(mgmd, randomAllowedType, &nodeId))
+    {
+      struct ndb_mgm_configuration* conf =
+        ndb_mgm_get_configuration_from_node(mgmd.handle(), nodeId);
+      if (!conf)
+      {
+        g_err << "ndb_mgm_get_configuration_from_node "
+              << nodeId << " failed, error: "
+              << ndb_mgm_get_latest_error(mgmd.handle()) << " "
+              << ndb_mgm_get_latest_error_msg(mgmd.handle()) << endl;
+        return NDBT_FAILED;
+      }
+      free(conf);
+    }
+    else
+    {
+      // ignore
+    }
+  }
+  return NDBT_OK;
+}
+
+
+int runGetConfigFromNodeUntilStopped(NDBT_Context* ctx, NDBT_Step* step)
+{
+  int result= NDBT_OK;
+  while(!ctx->isTestStopped() &&
+        (result= runGetConfigFromNode(ctx, step)) == NDBT_OK)
+    ;
+  return result;
+}
+
+
 int runTestStatus(NDBT_Context* ctx, NDBT_Step* step)
 {
   ndb_mgm_node_type types[2] = {
@@ -2659,6 +2828,7 @@ TESTCASE("Stress",
   STEP(runTestGetNodeIdUntilStopped);
   STEP(runSetConfigUntilStopped);
   STEPS(runGetConfigUntilStopped, 10);
+  STEPS(runGetConfigFromNodeUntilStopped, 10);
   STEPS(runTestStatusUntilStopped, 10);
   STEPS(runTestGetVersionUntilStopped, 5);
   STEP(runSleepAndStop);
@@ -2668,6 +2838,7 @@ TESTCASE("Stress2",
   STEP(runTestGetNodeIdUntilStopped);
   STEPS(runTestSetConfigParallelUntilStopped, 5);
   STEPS(runGetConfigUntilStopped, 10);
+  STEPS(runGetConfigFromNodeUntilStopped, 10);
   STEPS(runTestStatusUntilStopped, 10);
   STEPS(runTestGetVersionUntilStopped, 5);
   STEP(runSleepAndStop);

=== modified file 'storage/ndb/test/src/NDBT_Find.cpp'
--- a/storage/ndb/test/src/NDBT_Find.cpp	2011-02-02 00:40:07 +0000
+++ b/storage/ndb/test/src/NDBT_Find.cpp	2011-07-04 08:23:19 +0000
@@ -48,11 +48,22 @@ NDBT_find_binary(BaseString& name, const
     {
       // Sucess, found the binary. Convert path to absolute and return it
       char realpath_buf[PATH_MAX];
+#ifndef _WIN32
       if (realpath(path.c_str(), realpath_buf) == NULL)
       {
         fprintf(stderr, "Could not convert '%s' to realpath\n", path.c_str());
         abort();
       }
+#else
+      int ret= GetFullPathName(path.c_str(), sizeof(realpath_buf),
+                               realpath_buf, NULL);
+      if (ret == 0 || ret >= sizeof(realpath_buf))
+      {
+        fprintf(stderr, "Could not convert '%s' with GetFullPathName\n",
+                path.c_str());
+        abort();
+      }
+#endif
 
       name.assign(realpath_buf);
       return;

=== modified file 'storage/ndb/tools/ndb_config.cpp'
--- a/storage/ndb/tools/ndb_config.cpp	2011-05-24 12:19:31 +0000
+++ b/storage/ndb/tools/ndb_config.cpp	2011-07-04 08:31:41 +0000
@@ -16,7 +16,45 @@
 */
 
 /**
- * ndb_config --nodes --query=nodeid --type=ndbd --host=local1
+ * Description of config variables, including their min, max, default
+ * values can be printed (--configinfo). This can also be printed
+ * in xml format (--xml).
+ *
+ * Config can be retrieved from only one of the following sources:
+ ** config stored at mgmd (default. The options --config_from_node=0,
+ ** or --config_from_node=1 also give the same results.)
+ ** config stored at a data node (--config_from_node)
+ ** my.cnf (--mycnf=<fullPath/mycnfFileName>)
+ ** config.file  (--config_file=<fullPath/configFileName>
+ *
+ * Config variables are displayed from only one of the following
+ * sections of the retrieved config:
+ ** CFG_SECTION_NODE (default, or --nodes)
+ ** CFG_SECTION_CONNECTION (--connections)
+ ** CFG_SECTION_SYSTEM (--system)
+ */
+
+/**
+ * Examples:
+ * Get config from mgmd (default):
+ ** Display results from section CFG_SECTION_NODE (default)
+ *** ndb_config --nodes --query=nodeid --type=ndbd --host=local1
+ *** ndb_config  --query=nodeid,host
+ *
+ ** Display results from section CFG_SECTION_SYSTEM
+ *** ndb_config --system --query=ConfigGenerationNumber
+ *
+ ** Display results from section CFG_SECTION_CONNECTION
+ *** ndb_config --connections --query=type
+ *
+ * Get config from eg. node 2, which is a data node:
+ *
+ ** ndb_config --config_from_node=2 --system --query=ConfigGenerationNumber
+ ** ndb_config --config_from_node=2 --connections --query=type
+ ** ndb_config --config_from_node=2 --query=id,NoOfFragmentLogFiles
+ *
+ ** Display results for only node 2:
+ *** ndb_config --config_from_node=2 --query=id,NoOfFragmentLogFiles --nodeid=2
  */
 
 #include <ndb_global.h>
@@ -36,7 +74,7 @@
 static int g_verbose = 0;
 static int try_reconnect = 3;
 
-static int g_nodes, g_connections, g_section;
+static int g_nodes, g_connections, g_system, g_section;
 static const char * g_query = 0;
 
 static int g_nodeid = 0;
@@ -48,6 +86,7 @@ static const char * g_config_file = 0;
 static int g_mycnf = 0;
 static int g_configinfo = 0;
 static int g_xml = 0;
+static int g_config_from_node = 0;
 
 const char *load_default_groups[]= { "mysql_cluster",0 };
 
@@ -62,6 +101,9 @@ static struct my_option my_long_options[
   { "connections", NDB_OPT_NOSHORT, "Print connections",
     (uchar**) &g_connections, (uchar**) &g_connections,
     0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+  { "system", NDB_OPT_NOSHORT, "Print system",
+    (uchar**) &g_system, (uchar**) &g_system,
+    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
   { "query", 'q', "Query option(s)",
     (uchar**) &g_query, (uchar**) &g_query,
     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -95,6 +137,9 @@ static struct my_option my_long_options[
   { "xml", NDB_OPT_NOSHORT, "Print configinfo in xml format",
     (uchar**) &g_xml, (uchar**) &g_xml,
     0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+  { "config_from_node", NDB_OPT_NOSHORT, "Use current config from node with given nodeid",
+    (uchar**) &g_config_from_node, (uchar**) &g_config_from_node,
+    0, GET_INT, 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}
 };
 
@@ -154,7 +199,7 @@ static int parse_query(Vector<Apply*>&,
 static int parse_where(Vector<Match*>&, int &argc, char**& argv);
 static int eval(const Iter&, const Vector<Match*>&);
 static int apply(const Iter&, const Vector<Apply*>&);
-static ndb_mgm_configuration* fetch_configuration();
+static ndb_mgm_configuration* fetch_configuration(int from_node);
 static ndb_mgm_configuration* load_configuration();
 
 
@@ -178,23 +223,47 @@ main(int argc, char** argv){
     exit(0);
   }
 
-  if (g_nodes && g_connections)
+  if ((g_nodes && g_connections) ||
+       g_system && (g_nodes || g_connections))
   {
     fprintf(stderr,
-	    "Only one option of --nodes and --connections allowed\n");
+	    "Error: Only one of the section-options: --nodes, --connections, --system is allowed.\n");
+    exit(255);
+  }
+
+  /* There is no explicit option for the user to set
+   * 'retrieving config from mgmd', but this is the default.
+   * Therefore will not contradict with other sources.
+   */
+
+  if ((g_config_file && g_mycnf) ||
+       g_config_from_node && (g_config_file || g_mycnf))
+  {
+    fprintf(stderr,
+	    "Error: Config should be retrieved from only one of the following sources:\n");
+    fprintf(stderr,
+            "\tconfig stored at mgmd (default),\n");
+    fprintf(stderr,
+            "\tconfig stored at a data node (--config_from_node=<nodeid>), \n");
+    fprintf(stderr,
+            "\tmy.cnf(--mycnf=<my.cnf file>),\n");
+    fprintf(stderr,
+             "\tconfig.file (--config_file=<config file>).\n");
     exit(255);
   }
 
   g_section = CFG_SECTION_NODE; //default
   if (g_connections)
     g_section = CFG_SECTION_CONNECTION;
+  else if (g_system)
+    g_section = CFG_SECTION_SYSTEM;
 
   ndb_mgm_configuration * conf = 0;
 
   if (g_config_file || g_mycnf)
     conf = load_configuration();
   else
-    conf = fetch_configuration();
+    conf = fetch_configuration(g_config_from_node);
 
   if (conf == 0)
   {
@@ -289,7 +358,9 @@ parse_query(Vector<Apply*>& select, int
 	     (g_section == CFG_SECTION_NODE &&
               (strcmp(ConfigInfo::m_ParamInfo[p]._section, "DB") == 0 ||
                strcmp(ConfigInfo::m_ParamInfo[p]._section, "API") == 0 ||
-               strcmp(ConfigInfo::m_ParamInfo[p]._section, "MGM") == 0)))
+               strcmp(ConfigInfo::m_ParamInfo[p]._section, "MGM") == 0))
+             ||
+	     (g_section == CFG_SECTION_SYSTEM))
 	  {
 	    if(strcasecmp(ConfigInfo::m_ParamInfo[p]._fname, str) == 0)
 	    {
@@ -496,8 +567,8 @@ ConnectionTypeApply::apply(const Iter& i
 }
 
 static ndb_mgm_configuration*
-fetch_configuration()
-{  
+fetch_configuration(int from_node)
+{
   ndb_mgm_configuration* conf = 0;
   NdbMgmHandle mgm = ndb_mgm_create_handle();
   if(mgm == NULL) {
@@ -532,11 +603,17 @@ fetch_configuration()
 	    ndb_mgm_get_connected_port(mgm));
   }
 	  
-  conf = ndb_mgm_get_configuration(mgm, 0);
+  if (from_node > 1)
+  {
+    conf = ndb_mgm_get_configuration_from_node(mgm, from_node);
+  }
+  else
+     conf = ndb_mgm_get_configuration(mgm, 0);
+
   if(conf == 0)
   {
-    fprintf(stderr, "Could not get configuration");
-    fprintf(stderr, "code: %d, msg: %s\n",
+    fprintf(stderr, "Could not get configuration, ");
+    fprintf(stderr, "error code: %d, error msg: %s\n",
 	    ndb_mgm_get_latest_error(mgm),
 	    ndb_mgm_get_latest_error_msg(mgm));
   }

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-5.5-cluster branch (jonas.oreland:3415 to 3418) jonas oreland4 Jul