3513 Ole John Aske 2011-06-22 [merge]
merged mysql-5.1-telco-7.0 -> mysql-5.1-telco-7.0-spj-scan-scan
modified:
mysql-test/t/ctype_cp932_binlog_stm.test
sql/ha_ndb_index_stat.cc
sql/ha_ndbcluster.cc
sql/ha_ndbcluster.h
storage/ndb/include/mgmapi/mgmapi.h
storage/ndb/include/mgmapi/ndb_logevent.h
storage/ndb/include/ndb_types.h.in
storage/ndb/src/CMakeLists.txt
storage/ndb/src/common/debugger/CMakeLists.txt
storage/ndb/src/common/debugger/signaldata/CMakeLists.txt
storage/ndb/src/common/logger/CMakeLists.txt
storage/ndb/src/common/mgmcommon/CMakeLists.txt
storage/ndb/src/common/portlib/CMakeLists.txt
storage/ndb/src/common/transporter/CMakeLists.txt
storage/ndb/src/common/transporter/TransporterRegistry.cpp
storage/ndb/src/common/util/CMakeLists.txt
storage/ndb/src/kernel/CMakeLists.txt
storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
storage/ndb/src/mgmapi/CMakeLists.txt
storage/ndb/src/mgmapi/mgmapi.cpp
storage/ndb/src/mgmsrv/CMakeLists.txt
storage/ndb/src/mgmsrv/MgmtSrvr.cpp
storage/ndb/src/mgmsrv/MgmtSrvr.hpp
storage/ndb/src/ndbapi/CMakeLists.txt
storage/ndb/src/ndbapi/ClusterMgr.cpp
storage/ndb/test/ndbapi/testBasic.cpp
storage/ndb/test/ndbapi/testMgmd.cpp
storage/ndb/tools/ndb_dump_frm_data.cpp
3512 Jan Wedvik 2011-06-21
This patch turns of measuring SCAN_ROWS_RETURNED for certain bushy scan
queries. The reason for this is that growth of this counter is platform
dependent for these queries. There are two reasons for this:
1. Distribution hashing (partitioning) of tables is endian dependent. This
may cause data to be more skewed on some platforms. This again requires more
batches to scan the table and thus more repeats of repeatable scans (i.e.
those that will be repeated for each batch of the other branch of a bushy
scan). This increases the overall scan row count.
2. If a timer expires in LQH after receiving SCAN_FRAGREQ, LQH may decide to
send SCAN_FRAGCONF immediately, even if more tuples could fit in the batch.
As above this causes more repeats of repeatable scans.
modified:
mysql-test/suite/ndb/r/ndb_join_pushdown.result
mysql-test/suite/ndb/t/ndb_join_pushdown.test
=== modified file 'mysql-test/t/ctype_cp932_binlog_stm.test'
--- a/mysql-test/t/ctype_cp932_binlog_stm.test 2011-01-06 21:19:05 +0000
+++ b/mysql-test/t/ctype_cp932_binlog_stm.test 2011-06-22 12:21:58 +0000
@@ -34,7 +34,7 @@ delimiter ;|
# the log's contents) that caused the server crash.
-- disable_query_log
-call mtr.add_suppression("Error in Log_event::read_log_event\\\(\\\): 'read error', data_len: 66125, event_type: 116");
+call mtr.add_suppression("Error in Log_event::read_log_event\\\(\\\): 'read error', data_len: 66126, event_type: 116");
-- enable_query_log
--error 1220
=== modified file 'sql/ha_ndb_index_stat.cc'
--- a/sql/ha_ndb_index_stat.cc 2011-06-16 11:36:45 +0000
+++ b/sql/ha_ndb_index_stat.cc 2011-06-22 07:37:51 +0000
@@ -70,7 +70,7 @@ struct Ndb_index_stat {
int lt_old; /* for info only */
struct Ndb_index_stat *list_next;
struct Ndb_index_stat *list_prev;
- struct st_ndbcluster_share *share;
+ struct NDB_SHARE *share;
Ndb_index_stat();
};
@@ -1585,20 +1585,20 @@ ndb_index_stat_thread_func(void *arg __a
/*
wait for mysql server to start
*/
- pthread_mutex_lock(&LOCK_server_started);
+ mysql_mutex_lock(&LOCK_server_started);
while (!mysqld_server_started)
{
set_timespec(abstime, 1);
- pthread_cond_timedwait(&COND_server_started, &LOCK_server_started,
- &abstime);
+ mysql_cond_timedwait(&COND_server_started, &LOCK_server_started,
+ &abstime);
if (ndbcluster_terminating)
{
- pthread_mutex_unlock(&LOCK_server_started);
+ mysql_mutex_unlock(&LOCK_server_started);
pthread_mutex_lock(&LOCK_ndb_index_stat_thread);
goto ndb_index_stat_thread_end;
}
}
- pthread_mutex_unlock(&LOCK_server_started);
+ mysql_mutex_unlock(&LOCK_server_started);
/*
Wait for cluster to start
@@ -1650,10 +1650,8 @@ ndb_index_stat_thread_func(void *arg __a
goto ndb_index_stat_thread_end;
pthread_mutex_unlock(&LOCK_ndb_index_stat_thread);
- pthread_mutex_lock(&LOCK_global_system_variables);
/* const bool enable_ok_new= THDVAR(NULL, index_stat_enable); */
const bool enable_ok_new= ndb_index_stat_get_enable(NULL);
- pthread_mutex_unlock(&LOCK_global_system_variables);
Ndb_index_stat_proc pr;
pr.ndb= thd_ndb->ndb;
=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc 2011-06-20 14:40:46 +0000
+++ b/sql/ha_ndbcluster.cc 2011-06-22 12:21:58 +0000
@@ -284,7 +284,10 @@ static MYSQL_THDVAR_BOOL(
*/
bool ndb_index_stat_get_enable(THD *thd)
{
- return THDVAR(thd, index_stat_enable);
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ const bool value = THDVAR(thd, index_stat_enable);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ return value;
}
/*
@@ -11593,7 +11596,7 @@ static int ndbcluster_init(void *p)
if (pthread_create(&tmp2, &connection_attrib, ndb_index_stat_thread_func, 0))
{
DBUG_PRINT("error", ("Could not create ndb index statistics thread"));
- hash_free(&ndbcluster_open_tables);
+ my_hash_free(&ndbcluster_open_tables);
pthread_mutex_destroy(&ndbcluster_mutex);
pthread_mutex_destroy(&LOCK_ndb_index_stat_thread);
pthread_cond_destroy(&COND_ndb_index_stat_thread);
@@ -11614,7 +11617,7 @@ static int ndbcluster_init(void *p)
if (!ndb_index_stat_thread_running)
{
DBUG_PRINT("error", ("ndb index statistics thread exited prematurely"));
- hash_free(&ndbcluster_open_tables);
+ my_hash_free(&ndbcluster_open_tables);
pthread_mutex_destroy(&ndbcluster_mutex);
pthread_mutex_destroy(&LOCK_ndb_index_stat_thread);
pthread_cond_destroy(&COND_ndb_index_stat_thread);
=== modified file 'sql/ha_ndbcluster.h'
--- a/sql/ha_ndbcluster.h 2011-06-20 14:40:46 +0000
+++ b/sql/ha_ndbcluster.h 2011-06-22 12:21:58 +0000
@@ -45,7 +45,6 @@ class NdbIndexScanOperation;
class NdbBlob;
class NdbIndexStat;
class NdbEventOperation;
-class NdbInterpretedCode;
class ha_ndbcluster_cond;
class Ndb_event_data;
class NdbQuery;
@@ -176,7 +175,7 @@ typedef int (* prepare_detect_func) (str
const uchar* old_data,
const uchar* new_data,
const MY_BITMAP* write_set,
- NdbInterpretedCode* code);
+ class NdbInterpretedCode* code);
struct st_conflict_fn_def
{
@@ -196,7 +195,7 @@ enum enum_conflict_cause
/* NdbOperation custom data which points out handler and record. */
struct Ndb_exceptions_data {
- struct st_ndbcluster_share *share;
+ struct NDB_SHARE* share;
const NdbRecord* key_rec;
const uchar* row;
enum_conflicting_op_type op_type;
@@ -235,7 +234,7 @@ struct Ndb_statistics {
Uint64 fragment_extent_free_space;
};
-typedef struct st_ndbcluster_share {
+struct NDB_SHARE {
NDB_SHARE_STATE state;
MEM_ROOT mem_root;
THR_LOCK lock;
@@ -262,7 +261,7 @@ typedef struct st_ndbcluster_share {
char *old_names; // for rename table
MY_BITMAP *subscriber_bitmap;
NdbEventOperation *new_op;
-} NDB_SHARE;
+};
inline
NDB_SHARE_STATE
@@ -916,7 +915,7 @@ private:
key_range *max_key,
ha_rows *rows_out);
int ndb_index_stat_set_rpk(uint inx);
- int ndb_index_stat_wait(Ndb_index_stat *st,
+ int ndb_index_stat_wait(struct Ndb_index_stat *st,
uint sample_version);
int ndb_index_stat_query(uint inx,
const key_range *min_key,
=== modified file 'storage/ndb/include/mgmapi/mgmapi.h'
--- a/storage/ndb/include/mgmapi/mgmapi.h 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/include/mgmapi/mgmapi.h 2011-06-21 13:10:37 +0000
@@ -206,11 +206,13 @@ extern "C" {
NDB_MGM_NODE_STATUS_SINGLEUSER = 7,
/** Resume mode*/
NDB_MGM_NODE_STATUS_RESUME = 8,
+ /** Node is connected */
+ NDB_MGM_NODE_STATUS_CONNECTED = 9,
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
/** Min valid value*/
NDB_MGM_NODE_STATUS_MIN = 0,
/** Max valid value*/
- NDB_MGM_NODE_STATUS_MAX = 8
+ NDB_MGM_NODE_STATUS_MAX = 9
#endif
};
=== modified file 'storage/ndb/include/mgmapi/ndb_logevent.h'
--- a/storage/ndb/include/mgmapi/ndb_logevent.h 2011-04-09 15:48:21 +0000
+++ b/storage/ndb/include/mgmapi/ndb_logevent.h 2011-06-22 08:04:19 +0000
@@ -371,6 +371,7 @@ extern "C" {
unsigned version;
};
struct ndb_logevent_STTORRYRecieved {
+ unsigned unused;
};
struct ndb_logevent_StartPhaseCompleted {
unsigned phase;
@@ -407,6 +408,7 @@ extern "C" {
unsigned extra;
};
struct ndb_logevent_NDBStopAborted {
+ unsigned _unused;
};
struct ndb_logevent_StartREDOLog {
unsigned node;
@@ -436,8 +438,10 @@ extern "C" {
/* NODERESTART */
struct ndb_logevent_NR_CopyDict {
+ unsigned _unused;
};
struct ndb_logevent_NR_CopyDistr {
+ unsigned _unused;
};
struct ndb_logevent_NR_CopyFragsStarted {
unsigned dest_node;
@@ -475,10 +479,13 @@ extern "C" {
/* TODO */
};
struct ndb_logevent_GCP_TakeoverStarted {
+ unsigned _unused;
};
struct ndb_logevent_GCP_TakeoverCompleted {
+ unsigned _unused;
};
struct ndb_logevent_LCP_TakeoverStarted {
+ unsigned _unused;
};
struct ndb_logevent_LCP_TakeoverCompleted {
unsigned state;
@@ -561,6 +568,7 @@ extern "C" {
};
struct ndb_logevent_WarningEvent {
/* TODO */
+ unsigned _unused;
};
/* INFO */
@@ -572,6 +580,7 @@ extern "C" {
};
struct ndb_logevent_InfoEvent {
/* TODO */
+ unsigned _unused;
};
struct ndb_logevent_EventBufferStatus {
unsigned usage;
@@ -722,21 +731,21 @@ extern "C" {
unsigned objectid;
unsigned version;
unsigned type;
- unsigned node; // Node create object
+ unsigned node; /* Node create object */
};
struct ndb_logevent_AlterSchemaObject {
unsigned objectid;
unsigned version;
unsigned type;
- unsigned node; // Node create object
+ unsigned node; /* Node create object */
};
struct ndb_logevent_DropSchemaObject {
unsigned objectid;
unsigned version;
unsigned type;
- unsigned node; // Node create object
+ unsigned node; /* Node create object */
};
struct ndb_logevent_StartReadLCP {
=== modified file 'storage/ndb/include/ndb_types.h.in'
--- a/storage/ndb/include/ndb_types.h.in 2011-02-01 23:27:25 +0000
+++ b/storage/ndb/include/ndb_types.h.in 2011-06-22 08:04:19 +0000
@@ -47,15 +47,15 @@ typedef unsigned int Uint32;
#ifndef INT_MIN64
#define INT_MIN64 (~0x7FFFFFFFFFFFFFFFLL)
-#endif // !INT_MIN64
+#endif /* !INT_MIN64 */
#ifndef INT_MAX64
#define INT_MAX64 0x7FFFFFFFFFFFFFFFLL
-#endif // !INT_MAX64
+#endif /* !INT_MAX64 */
#ifndef UINT_MAX64
#define UINT_MAX64 0xFFFFFFFFFFFFFFFFLL
-#endif // !UINT_MAX64
+#endif /* !UINT_MAX64 */
typedef unsigned int UintR;
=== modified file 'storage/ndb/src/CMakeLists.txt'
--- a/storage/ndb/src/CMakeLists.txt 2011-02-02 00:40:07 +0000
+++ b/storage/ndb/src/CMakeLists.txt 2011-06-20 08:31:14 +0000
@@ -32,7 +32,7 @@ SET(NDBCLIENT_LIBS
ndbtrace
ndbsignaldata
ndbmgmapi
- ndbmgmsrv
+ ndbmgmcommon
ndblogger
ndbportlib
ndbgeneral
=== modified file 'storage/ndb/src/common/debugger/CMakeLists.txt'
--- a/storage/ndb/src/common/debugger/CMakeLists.txt 2011-02-02 00:40:07 +0000
+++ b/storage/ndb/src/common/debugger/CMakeLists.txt 2011-06-21 14:05:31 +0000
@@ -18,7 +18,7 @@ ADD_SUBDIRECTORY(signaldata)
INCLUDE(${CMAKE_SOURCE_DIR}/storage/ndb/config/type_kernel.cmake)
-ADD_LIBRARY(ndbtrace STATIC
+ADD_CONVENIENCE_LIBRARY(ndbtrace
SignalLoggerManager.cpp
DebuggerNames.cpp
BlockNames.cpp
@@ -26,4 +26,4 @@ ADD_LIBRARY(ndbtrace STATIC
${NDB_SOURCE_DIR}/src/kernel/error/ndbd_exit_codes.c
)
-TARGET_LINK_LIBRARIES(ndbtrace ndblogger ndbgeneral)
+TARGET_LINK_LIBRARIES(ndbtrace ndbsignaldata ndblogger ndbgeneral)
=== modified file 'storage/ndb/src/common/debugger/signaldata/CMakeLists.txt'
--- a/storage/ndb/src/common/debugger/signaldata/CMakeLists.txt 2011-05-23 15:46:53 +0000
+++ b/storage/ndb/src/common/debugger/signaldata/CMakeLists.txt 2011-06-21 13:58:00 +0000
@@ -13,7 +13,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-ADD_LIBRARY(ndbsignaldata STATIC
+ADD_CONVENIENCE_LIBRARY(ndbsignaldata
AlterIndxImpl.cpp BuildIndxImpl.cpp BuildIndx.cpp
CreateIndxImpl.cpp CreateTab.cpp
CreateTable.cpp CreateTrigImpl.cpp #DihSwitchReplicaReq.cpp
=== modified file 'storage/ndb/src/common/logger/CMakeLists.txt'
--- a/storage/ndb/src/common/logger/CMakeLists.txt 2011-02-02 00:40:07 +0000
+++ b/storage/ndb/src/common/logger/CMakeLists.txt 2011-06-21 13:58:00 +0000
@@ -13,7 +13,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-ADD_LIBRARY(ndblogger STATIC
+ADD_CONVENIENCE_LIBRARY(ndblogger
Logger.cpp
LogHandlerList.cpp
LogHandler.cpp
=== modified file 'storage/ndb/src/common/mgmcommon/CMakeLists.txt'
--- a/storage/ndb/src/common/mgmcommon/CMakeLists.txt 2011-02-02 00:40:07 +0000
+++ b/storage/ndb/src/common/mgmcommon/CMakeLists.txt 2011-06-21 14:07:12 +0000
@@ -18,7 +18,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/
${CMAKE_SOURCE_DIR}/storage/ndb/src/mgmsrv)
INCLUDE(${CMAKE_SOURCE_DIR}/storage/ndb/config/type_mgmapiclient.cmake)
-ADD_LIBRARY(ndbmgmsrv STATIC
- ConfigRetriever.cpp
- IPCConfig.cpp)
+ADD_CONVENIENCE_LIBRARY(ndbmgmcommon
+ ConfigRetriever.cpp
+ IPCConfig.cpp)
=== modified file 'storage/ndb/src/common/portlib/CMakeLists.txt'
--- a/storage/ndb/src/common/portlib/CMakeLists.txt 2011-05-25 06:52:33 +0000
+++ b/storage/ndb/src/common/portlib/CMakeLists.txt 2011-06-22 06:19:13 +0000
@@ -22,7 +22,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/
IF(WIN32)
SET(EXTRA_SRC ${CMAKE_SOURCE_DIR}/sql/nt_servc.cc)
ENDIF(WIN32)
-ADD_LIBRARY(ndbportlib STATIC
+ADD_CONVENIENCE_LIBRARY(ndbportlib
NdbCondition.c NdbMutex.c ndb_socket.cpp
NdbEnv.c NdbThread.c NdbHost.c NdbTCP.cpp
NdbMem.c NdbConfig.c NdbTick.c NdbDir.cpp
=== modified file 'storage/ndb/src/common/transporter/CMakeLists.txt'
--- a/storage/ndb/src/common/transporter/CMakeLists.txt 2011-02-02 00:40:07 +0000
+++ b/storage/ndb/src/common/transporter/CMakeLists.txt 2011-06-21 13:58:00 +0000
@@ -22,7 +22,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/
${CMAKE_SOURCE_DIR}/storage/ndb/include/transporter
${NDB_SCI_INCLUDES})
-ADD_LIBRARY(ndbtransport STATIC
+ADD_CONVENIENCE_LIBRARY(ndbtransport
Transporter.cpp TCP_Transporter.cpp Loopback_Transporter.cpp
TransporterRegistry.cpp Packer.cpp)
=== modified file 'storage/ndb/src/common/transporter/TransporterRegistry.cpp'
--- a/storage/ndb/src/common/transporter/TransporterRegistry.cpp 2011-06-01 07:40:49 +0000
+++ b/storage/ndb/src/common/transporter/TransporterRegistry.cpp 2011-06-15 13:24:40 +0000
@@ -1002,7 +1002,7 @@ TransporterRegistry::pollReceive(Uint32
{
for (int i = 0; i < num_socket_events; i++)
{
- Uint32 trpid = m_epoll_events[i].data.u32;
+ const Uint32 trpid = m_epoll_events[i].data.u32;
#ifdef ERROR_INSERT
if (m_blocked.get(trpid))
{
@@ -1011,7 +1011,7 @@ TransporterRegistry::pollReceive(Uint32
continue;
}
#endif
- mask.set(m_epoll_events[i].data.u32);
+ mask.set(trpid);
}
}
else if (num_socket_events < 0)
=== modified file 'storage/ndb/src/common/util/CMakeLists.txt'
--- a/storage/ndb/src/common/util/CMakeLists.txt 2011-05-09 15:35:25 +0000
+++ b/storage/ndb/src/common/util/CMakeLists.txt 2011-06-21 13:58:00 +0000
@@ -25,7 +25,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOUR
${CMAKE_SOURCE_DIR}/storage/ndb/include/logger)
ADD_DEFINITIONS(-DNO_DUMMY_DECL)
-ADD_LIBRARY(ndbgeneral STATIC
+ADD_CONVENIENCE_LIBRARY(ndbgeneral
ndbzio.c
File.cpp
md5_hash.cpp
=== modified file 'storage/ndb/src/kernel/CMakeLists.txt'
--- a/storage/ndb/src/kernel/CMakeLists.txt 2011-02-24 07:39:24 +0000
+++ b/storage/ndb/src/kernel/CMakeLists.txt 2011-06-22 12:21:58 +0000
@@ -42,7 +42,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOUR
)
SET(NDBD_LIBS ndbblocks ndbkernel ndberror ndbtransport
- ndbtrace ndbsignaldata ndblogger ndbmgmsrv ndbmgmapi
+ ndbtrace ndbsignaldata ndblogger ndbmgmcommon ndbmgmapi
ndbportlib ndbgeneral dbug mysys strings
)
=== modified file 'storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp'
--- a/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp 2011-06-15 10:40:26 +0000
+++ b/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp 2011-06-22 12:21:58 +0000
@@ -3728,6 +3728,7 @@ Qmgr::execAPI_VERSION_REQ(Signal * signa
else
{
conf->version = 0;
+ conf->mysql_version = 0;
conf->inet_addr= 0;
}
conf->nodeId = nodeId;
=== modified file 'storage/ndb/src/mgmapi/CMakeLists.txt'
--- a/storage/ndb/src/mgmapi/CMakeLists.txt 2011-02-02 00:40:07 +0000
+++ b/storage/ndb/src/mgmapi/CMakeLists.txt 2011-06-21 13:58:00 +0000
@@ -20,7 +20,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/
${CMAKE_SOURCE_DIR}/storage/ndb/mgmsrv
)
ADD_DEFINITIONS(-DNDB_MGMAPI)
-ADD_LIBRARY(ndbmgmapi STATIC
+ADD_CONVENIENCE_LIBRARY(ndbmgmapi
mgmapi.cpp
mgmapi_error.c
ndb_logevent.cpp
=== modified file 'storage/ndb/src/mgmapi/mgmapi.cpp'
--- a/storage/ndb/src/mgmapi/mgmapi.cpp 2011-03-28 09:01:03 +0000
+++ b/storage/ndb/src/mgmapi/mgmapi.cpp 2011-06-21 13:10:37 +0000
@@ -934,7 +934,10 @@ static struct ndb_mgm_status_atoi status
{ "STARTED", NDB_MGM_NODE_STATUS_STARTED },
{ "SHUTTING_DOWN", NDB_MGM_NODE_STATUS_SHUTTING_DOWN },
{ "RESTARTING", NDB_MGM_NODE_STATUS_RESTARTING },
- { "SINGLE USER MODE", NDB_MGM_NODE_STATUS_SINGLEUSER }
+ { "SINGLE USER MODE", NDB_MGM_NODE_STATUS_SINGLEUSER },
+ { "SINGLE USER MODE", NDB_MGM_NODE_STATUS_SINGLEUSER },
+ { "RESUME", NDB_MGM_NODE_STATUS_RESUME },
+ { "CONNECTED", NDB_MGM_NODE_STATUS_CONNECTED }
};
const int no_of_status_values = (sizeof(status_values) /
=== modified file 'storage/ndb/src/mgmsrv/CMakeLists.txt'
--- a/storage/ndb/src/mgmsrv/CMakeLists.txt 2011-02-03 14:20:36 +0000
+++ b/storage/ndb/src/mgmsrv/CMakeLists.txt 2011-06-21 13:58:00 +0000
@@ -18,7 +18,7 @@ INCLUDE_DIRECTORIES(
${NDB_SOURCE_DIR}/src/ndbapi
${NDB_SOURCE_DIR}/src/mgmclient)
-ADD_LIBRARY(ndbconf
+ADD_CONVENIENCE_LIBRARY(ndbconf
Config.cpp
ConfigInfo.cpp
InitConfigFileParser.cpp
=== modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.cpp'
--- a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp 2011-06-01 07:40:49 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp 2011-06-22 08:57:03 +0000
@@ -42,7 +42,6 @@
#include <signaldata/SchemaTrans.hpp>
#include <signaldata/CreateNodegroup.hpp>
#include <signaldata/DropNodegroup.hpp>
-#include <signaldata/DbinfoScan.hpp>
#include <signaldata/Sync.hpp>
#include <NdbSleep.h>
#include <portlib/NdbDir.hpp>
@@ -835,59 +834,34 @@ MgmtSrvr::start(int nodeId)
* Version handling
*****************************************************************************/
-int
-MgmtSrvr::versionNode(int nodeId, Uint32 &version, Uint32& mysql_version,
- const char **address)
-{
- version= 0;
- mysql_version = 0;
- if (getOwnNodeId() == nodeId)
- {
- /**
- * If we're inquiring about our own node id,
- * We know what version we are (version implies connected for mgm)
- * but would like to find out from elsewhere what address they're using
- * to connect to us. This means that secondary mgm servers
- * can list ip addresses for mgm servers.
- *
- * If we don't get an address (i.e. no db nodes),
- * we get the address from the configuration.
- */
- sendVersionReq(nodeId, version, mysql_version, address);
- version= NDB_VERSION;
- mysql_version = NDB_MYSQL_VERSION_D;
- if(!*address)
- {
- Guard g(m_local_config_mutex);
- ConfigIter iter(m_local_config, CFG_SECTION_NODE);
- unsigned tmp= 0;
- for(iter.first();iter.valid();iter.next())
- {
- if(iter.get(CFG_NODE_ID, &tmp)) require(false);
- if((unsigned)nodeId!=tmp)
- continue;
- if(iter.get(CFG_NODE_HOST, address)) require(false);
- break;
- }
- }
+void
+MgmtSrvr::status_api(int nodeId,
+ ndb_mgm_node_status& node_status,
+ Uint32& version, Uint32& mysql_version,
+ const char **address)
+{
+ assert(getNodeType(nodeId) == NDB_MGM_NODE_TYPE_API);
+ assert(version == 0 && mysql_version == 0);
+
+ if (sendVersionReq(nodeId, version, mysql_version, address) != 0)
+ {
+ // Couldn't get version from any NDB node.
+ assert(version == 0);
+ node_status = NDB_MGM_NODE_STATUS_UNKNOWN;
+ return;
}
- else if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_NDB)
+
+ if (version)
{
- trp_node node = getNodeInfo(nodeId);
- if(node.is_connected())
- {
- version= node.m_info.m_version;
- mysql_version = node.m_info.m_mysql_version;
- }
- *address= get_connect_address(nodeId);
+ assert(mysql_version);
+ node_status = NDB_MGM_NODE_STATUS_CONNECTED;
}
- else if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_API ||
- getNodeType(nodeId) == NDB_MGM_NODE_TYPE_MGM)
+ else
{
- return sendVersionReq(nodeId, version, mysql_version, address);
+ assert(mysql_version == 0);
+ node_status = NDB_MGM_NODE_STATUS_NO_CONTACT;
}
-
- return 0;
+ return;
}
@@ -907,8 +881,8 @@ MgmtSrvr::sendVersionReq(int v_nodeId,
ssig.set(ss, TestOrd::TraceAPI, QMGR,
GSN_API_VERSION_REQ, ApiVersionReq::SignalLength);
- NodeId nodeId;
- int do_send = 1;
+ NodeId nodeId = 0;
+ bool do_send = true;
while(true)
{
if (do_send)
@@ -924,7 +898,7 @@ MgmtSrvr::sendVersionReq(int v_nodeId,
return SEND_OR_RECEIVE_FAILED;
}
- do_send = 0;
+ do_send = false;
}
SimpleSignal *signal = ss.waitFor();
@@ -951,7 +925,7 @@ MgmtSrvr::sendVersionReq(int v_nodeId,
const NFCompleteRep * const rep =
CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr());
if (rep->failedNodeId == nodeId)
- do_send = 1; // retry with other node
+ do_send = true; // retry with other node
continue;
}
@@ -959,7 +933,7 @@ MgmtSrvr::sendVersionReq(int v_nodeId,
const NodeFailRep * const rep =
CAST_CONSTPTR(NodeFailRep, signal->getDataPtr());
if (NdbNodeBitmask::get(rep->theNodes,nodeId))
- do_send = 1; // retry with other node
+ do_send = true; // retry with other node
continue;
}
case GSN_API_REGCONF:
@@ -1486,11 +1460,11 @@ int MgmtSrvr::shutdownMGM(int *stopCount
error= sendStopMgmd(nodeId, abort, true, false,
false, false);
if (error == 0)
- *stopCount++;
+ (*stopCount)++;
}
*stopSelf= 1;
- *stopCount++;
+ (*stopCount)++;
return 0;
}
@@ -1898,6 +1872,75 @@ MgmtSrvr::updateStatus()
theFacade->ext_forceHB();
}
+
+void
+MgmtSrvr::status_mgmd(NodeId node_id,
+ ndb_mgm_node_status& node_status,
+ Uint32& version, Uint32& mysql_version,
+ const char **address)
+{
+ assert(getNodeType(node_id) == NDB_MGM_NODE_TYPE_MGM);
+
+ if (node_id == getOwnNodeId())
+ {
+ /*
+ Special case to get version of own node
+ - version and mysql_version is hardcoded
+ - address should be the address seen from ndbd(if it's connected)
+ else use HostName from config
+ */
+ Uint32 tmp_version = 0, tmp_mysql_version = 0;
+ sendVersionReq(node_id, tmp_version, tmp_mysql_version, address);
+ // Check that the version returned is equal to compiled in version
+ assert(tmp_version == 0 ||
+ (tmp_version == NDB_VERSION &&
+ tmp_mysql_version == NDB_MYSQL_VERSION_D));
+
+ version = NDB_VERSION;
+ mysql_version = NDB_MYSQL_VERSION_D;
+ if(!*address)
+ {
+ // No address returned from ndbd -> get HostName from config
+ Guard g(m_local_config_mutex);
+ ConfigIter iter(m_local_config, CFG_SECTION_NODE);
+ require(iter.find(CFG_NODE_ID, node_id) == 0);
+ require(iter.get(CFG_NODE_HOST, address) == 0);
+
+ /*
+ Try to convert HostName to numerical ip address
+ (to get same output as if ndbd had replied)
+ */
+ struct in_addr addr;
+ if (Ndb_getInAddr(&addr, *address) == 0)
+ *address = inet_ntoa(addr);
+ }
+
+ node_status = NDB_MGM_NODE_STATUS_CONNECTED;
+ return;
+ }
+
+ /*
+ MGM nodes are connected directly to all other MGM
+ node(s), return status as seen by ClusterMgr
+ */
+ const trp_node node = getNodeInfo(node_id);
+ if(node.is_connected())
+ {
+ version = node.m_info.m_version;
+ mysql_version = node.m_info.m_mysql_version;
+ node_status = NDB_MGM_NODE_STATUS_CONNECTED;
+ *address= get_connect_address(node_id);
+ }
+ else
+ {
+ version = 0;
+ mysql_version = 0;
+ node_status = NDB_MGM_NODE_STATUS_NO_CONTACT;
+ }
+
+ return;
+}
+
int
MgmtSrvr::status(int nodeId,
ndb_mgm_node_status * _status,
@@ -1910,24 +1953,38 @@ MgmtSrvr::status(int nodeId,
Uint32 * connectCount,
const char **address)
{
- if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_API ||
- getNodeType(nodeId) == NDB_MGM_NODE_TYPE_MGM) {
- versionNode(nodeId, *version, *mysql_version, address);
- } else {
- *address= get_connect_address(nodeId);
+ switch(getNodeType(nodeId)){
+ case NDB_MGM_NODE_TYPE_API:
+ status_api(nodeId, *_status, *version, *mysql_version, address);
+ return 0;
+ break;
+
+ case NDB_MGM_NODE_TYPE_MGM:
+ status_mgmd(nodeId, *_status, *version, *mysql_version, address);
+ return 0;
+ break;
+
+ case NDB_MGM_NODE_TYPE_NDB:
+ break;
+
+ default:
+ abort();
+ break;
}
const trp_node node = getNodeInfo(nodeId);
+ assert(getNodeType(nodeId) == NDB_MGM_NODE_TYPE_NDB &&
+ node.m_info.getType() == NodeInfo::DB);
if(!node.is_connected()){
* _status = NDB_MGM_NODE_STATUS_NO_CONTACT;
return 0;
}
-
- if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_NDB) {
- * version = node.m_info.m_version;
- * mysql_version = node.m_info.m_mysql_version;
- }
+
+ * version = node.m_info.m_version;
+ * mysql_version = node.m_info.m_mysql_version;
+
+ *address= get_connect_address(nodeId);
* dynamic = node.m_state.dynamicId;
* nodegroup = node.m_state.nodeGroup;
@@ -2792,9 +2849,10 @@ MgmtSrvr::getNodeType(NodeId nodeId) con
const char *MgmtSrvr::get_connect_address(Uint32 node_id)
{
- if (m_connect_address[node_id].s_addr == 0 &&
- theFacade &&
- getNodeType(node_id) == NDB_MGM_NODE_TYPE_NDB)
+ if (theFacade &&
+ m_connect_address[node_id].s_addr == 0 &&
+ (getNodeType(node_id) == NDB_MGM_NODE_TYPE_MGM ||
+ getNodeType(node_id) == NDB_MGM_NODE_TYPE_NDB))
{
const trp_node &node= getNodeInfo(node_id);
if (node.is_connected())
=== modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.hpp'
--- a/storage/ndb/src/mgmsrv/MgmtSrvr.hpp 2011-06-01 07:40:49 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.hpp 2011-06-21 13:10:37 +0000
@@ -364,8 +364,14 @@ public:
private:
int guess_master_node(SignalSender&);
- int versionNode(int nodeId, Uint32 &version,
- Uint32 &mysql_version, const char **address);
+ void status_api(int nodeId,
+ ndb_mgm_node_status& node_status,
+ Uint32& version, Uint32& mysql_version,
+ const char **address);
+ void status_mgmd(NodeId node_id,
+ ndb_mgm_node_status& node_status,
+ Uint32& version, Uint32& mysql_version,
+ const char **address);
int sendVersionReq(int processId, Uint32 &version,
Uint32& mysql_version, const char **address);
=== modified file 'storage/ndb/src/ndbapi/CMakeLists.txt'
--- a/storage/ndb/src/ndbapi/CMakeLists.txt 2011-06-17 12:41:11 +0000
+++ b/storage/ndb/src/ndbapi/CMakeLists.txt 2011-06-22 12:21:58 +0000
@@ -17,7 +17,7 @@ INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_SOURCE_DIR}
${NDB_SOURCE_DIR}/src/mgmapi)
-ADD_LIBRARY(ndbapi STATIC
+ADD_CONVENIENCE_LIBRARY(ndbapi
NdbEventOperation.cpp
NdbEventOperationImpl.cpp
NdbIndexStat.cpp
=== modified file 'storage/ndb/src/ndbapi/ClusterMgr.cpp'
--- a/storage/ndb/src/ndbapi/ClusterMgr.cpp 2011-02-03 14:20:36 +0000
+++ b/storage/ndb/src/ndbapi/ClusterMgr.cpp 2011-06-21 13:10:37 +0000
@@ -651,6 +651,9 @@ ClusterMgr::execAPI_REGREQ(const Uint32
if(node.m_info.m_version != apiRegReq->version){
node.m_info.m_version = apiRegReq->version;
+ node.m_info.m_mysql_version = apiRegReq->mysql_version;
+ if (node.m_info.m_version < NDBD_SPLIT_VERSION)
+ node.m_info.m_mysql_version = 0;
if (getMajor(node.m_info.m_version) < getMajor(NDB_VERSION) ||
getMinor(node.m_info.m_version) < getMinor(NDB_VERSION)) {
=== modified file 'storage/ndb/test/ndbapi/testBasic.cpp'
--- a/storage/ndb/test/ndbapi/testBasic.cpp 2011-05-25 13:19:02 +0000
+++ b/storage/ndb/test/ndbapi/testBasic.cpp 2011-06-20 07:17:57 +0000
@@ -3027,14 +3027,14 @@ static RefreshScenario refreshTests[] =
enum OpTypes
{
- READ_C,
- READ_S,
- READ_E,
- INSERT,
- UPDATE,
- WRITE,
- DELETE,
- LAST
+ OP_READ_C,
+ OP_READ_S,
+ OP_READ_E,
+ OP_INSERT,
+ OP_UPDATE,
+ OP_WRITE,
+ OP_DELETE,
+ OP_LAST
};
const char* opTypeNames[] =
@@ -3133,9 +3133,9 @@ runRefreshLocking(NDBT_Context* ctx, NDB
{
/* Now try ops from another transaction */
HugoOperations hugoOps(*ctx->getTab());
- Uint32 ot = READ_C;
+ Uint32 ot = OP_READ_C;
- while (ot < LAST)
+ while (ot < OP_LAST)
{
if (hugoOps.startTransaction(ndb) != 0)
{
@@ -3147,34 +3147,34 @@ runRefreshLocking(NDBT_Context* ctx, NDB
int res = 0;
switch (ot)
{
- case READ_C:
+ case OP_READ_C:
res = hugoOps.pkReadRecord(ndb,0,1,NdbOperation::LM_CommittedRead);
break;
- case READ_S:
+ case OP_READ_S:
res = hugoOps.pkReadRecord(ndb,0,1,NdbOperation::LM_Read);
break;
- case READ_E:
+ case OP_READ_E:
res = hugoOps.pkReadRecord(ndb,0,1,NdbOperation::LM_Exclusive);
break;
- case INSERT:
+ case OP_INSERT:
res = hugoOps.pkInsertRecord(ndb, 0);
break;
- case UPDATE:
+ case OP_UPDATE:
res = hugoOps.pkUpdateRecord(ndb, 0);
break;
- case WRITE:
+ case OP_WRITE:
res = hugoOps.pkWriteRecord(ndb, 0);
break;
- case DELETE:
+ case OP_DELETE:
res = hugoOps.pkDeleteRecord(ndb, 0);
break;
- case LAST:
+ case OP_LAST:
abort();
}
hugoOps.execute_Commit(ndb);
- if ((ot == READ_C) && (scenario.preExist))
+ if ((ot == OP_READ_C) && (scenario.preExist))
{
if (hugoOps.getNdbError().code == 0)
{
=== modified file 'storage/ndb/test/ndbapi/testMgmd.cpp'
--- a/storage/ndb/test/ndbapi/testMgmd.cpp 2011-02-03 14:20:36 +0000
+++ b/storage/ndb/test/ndbapi/testMgmd.cpp 2011-06-21 13:10:37 +0000
@@ -934,6 +934,171 @@ runBug56844(NDBT_Context* ctx, NDBT_Step
return NDBT_OK;
}
+static bool
+get_status(const char* connectstring,
+ Properties& status)
+{
+ NdbMgmd ndbmgmd;
+ if (!ndbmgmd.connect(connectstring))
+ return false;
+
+ Properties args;
+ if (!ndbmgmd.call("get status", args,
+ "node status", status, NULL, true))
+ {
+ g_err << "fetch_mgmd_status: mgmd.call failed" << endl;
+ return false;
+ }
+ return true;
+}
+
+static bool
+value_equal(Properties& status,
+ int nodeid, const char* name,
+ const char* expected_value)
+{
+ const char* value;
+ BaseString key;
+ key.assfmt("node.%d.%s", nodeid, name);
+ if (!status.get(key.c_str(), &value))
+ {
+ g_err << "value_equal: no value found for '" << name
+ << "." << nodeid << "'" << endl;
+ return false;
+ }
+
+ if (strcmp(value, expected_value))
+ {
+ g_err << "value_equal: found unexpected value: '" << value
+ << "', expected: '" << expected_value << "'" <<endl;
+ return false;
+ }
+ g_info << "'" << value << "'=='" << expected_value << "'" << endl;
+ return true;
+}
+
+#include <ndb_version.h>
+
+int runTestBug12352191(NDBT_Context* ctx, NDBT_Step* step)
+{
+ BaseString version;
+ version.assfmt("%u", NDB_VERSION_D);
+ BaseString mysql_version;
+ mysql_version.assfmt("%u", NDB_MYSQL_VERSION_D);
+ BaseString address("127.0.0.1");
+
+ NDBT_Workingdir wd("test_mgmd"); // temporary working directory
+
+ g_err << "** Create config.ini" << endl;
+ Properties config = ConfigFactory::create(2);
+ CHECK(ConfigFactory::write_config_ini(config,
+ path(wd.path(),
+ "config.ini",
+ NULL).c_str()));
+
+ MgmdProcessList mgmds;
+ const int nodeid1 = 1;
+ Mgmd* mgmd1 = new Mgmd(nodeid1);
+ mgmds.push_back(mgmd1);
+
+ const int nodeid2 = 2;
+ Mgmd* mgmd2 = new Mgmd(nodeid2);
+ mgmds.push_back(mgmd2);
+
+ // Start first mgmd
+ CHECK(mgmd1->start_from_config_ini(wd.path()));
+ CHECK(mgmd1->connect(config));
+
+ Properties status1;
+ CHECK(get_status(mgmd1->connectstring(config).c_str(), status1));
+ //status1.print();
+ // Check status for own mgm node, always CONNECTED
+ CHECK(value_equal(status1, nodeid1, "type", "MGM"));
+ CHECK(value_equal(status1, nodeid1, "status", "CONNECTED"));
+ CHECK(value_equal(status1, nodeid1, "version", version.c_str()));
+ CHECK(value_equal(status1, nodeid1, "mysql_version", mysql_version.c_str()));
+ CHECK(value_equal(status1, nodeid1, "address", address.c_str()));
+ CHECK(value_equal(status1, nodeid1, "startphase", "0"));
+ CHECK(value_equal(status1, nodeid1, "dynamic_id", "0"));
+ CHECK(value_equal(status1, nodeid1, "node_group", "0"));
+ CHECK(value_equal(status1, nodeid1, "connect_count", "0"));
+
+ // Check status for other mgm node
+ // not started yet -> NO_CONTACT, no address, no versions
+ CHECK(value_equal(status1, nodeid2, "type", "MGM"));
+ CHECK(value_equal(status1, nodeid2, "status", "NO_CONTACT"));
+ CHECK(value_equal(status1, nodeid2, "version", "0"));
+ CHECK(value_equal(status1, nodeid2, "mysql_version", "0"));
+ CHECK(value_equal(status1, nodeid2, "address", ""));
+ CHECK(value_equal(status1, nodeid2, "startphase", "0"));
+ CHECK(value_equal(status1, nodeid2, "dynamic_id", "0"));
+ CHECK(value_equal(status1, nodeid2, "node_group", "0"));
+ CHECK(value_equal(status1, nodeid2, "connect_count", "0"));
+
+ // Start second mgmd
+ CHECK(mgmd2->start_from_config_ini(wd.path()));
+ CHECK(mgmd2->connect(config));
+
+ // wait for confirmed config
+ for (unsigned i = 0; i < mgmds.size(); i++)
+ CHECK(mgmds[i]->wait_confirmed_config());
+
+ Properties status2;
+ CHECK(get_status(mgmd2->connectstring(config).c_str(), status2));
+ //status2.print();
+ // Check status for own mgm node, always CONNECTED
+ CHECK(value_equal(status2, nodeid2, "type", "MGM"));
+ CHECK(value_equal(status2, nodeid2, "status", "CONNECTED"));
+ CHECK(value_equal(status2, nodeid2, "version", version.c_str()));
+ CHECK(value_equal(status2, nodeid2, "mysql_version", mysql_version.c_str()));
+ CHECK(value_equal(status2, nodeid2, "address", address.c_str()));
+ CHECK(value_equal(status2, nodeid2, "startphase", "0"));
+ CHECK(value_equal(status2, nodeid2, "dynamic_id", "0"));
+ CHECK(value_equal(status2, nodeid2, "node_group", "0"));
+ CHECK(value_equal(status2, nodeid2, "connect_count", "0"));
+
+ // Check status for other mgm node
+ // both started now -> CONNECTED, address and versions filled in
+ CHECK(value_equal(status2, nodeid1, "type", "MGM"));
+ CHECK(value_equal(status2, nodeid1, "status", "CONNECTED"));
+ CHECK(value_equal(status2, nodeid1, "version", version.c_str()));
+ CHECK(value_equal(status2, nodeid1, "mysql_version", mysql_version.c_str()));
+ CHECK(value_equal(status2, nodeid1, "address", address.c_str()));
+ CHECK(value_equal(status2, nodeid1, "startphase", "0"));
+ CHECK(value_equal(status2, nodeid1, "dynamic_id", "0"));
+ CHECK(value_equal(status2, nodeid1, "node_group", "0"));
+ CHECK(value_equal(status2, nodeid1, "connect_count", "0"));
+
+ Properties status3;
+ CHECK(get_status(mgmd1->connectstring(config).c_str(), status3));
+ //status3.print();
+ // Check status for own mgm node, always CONNECTED
+ CHECK(value_equal(status3, nodeid1, "type", "MGM"));
+ CHECK(value_equal(status3, nodeid1, "status", "CONNECTED"));
+ CHECK(value_equal(status3, nodeid1, "version", version.c_str()));
+ CHECK(value_equal(status3, nodeid1, "mysql_version", mysql_version.c_str()));
+ CHECK(value_equal(status3, nodeid1, "address", address.c_str()));
+ CHECK(value_equal(status3, nodeid1, "startphase", "0"));
+ CHECK(value_equal(status3, nodeid1, "dynamic_id", "0"));
+ CHECK(value_equal(status3, nodeid1, "node_group", "0"));
+ CHECK(value_equal(status3, nodeid1, "connect_count", "0"));
+
+ // Check status for other mgm node
+ // both started now -> CONNECTED, address and versions filled in
+ CHECK(value_equal(status3, nodeid2, "type", "MGM"));
+ CHECK(value_equal(status3, nodeid2, "status", "CONNECTED"));
+ CHECK(value_equal(status3, nodeid2, "version", version.c_str()));
+ CHECK(value_equal(status3, nodeid2, "mysql_version", mysql_version.c_str()));
+ CHECK(value_equal(status3, nodeid2, "address", address.c_str()));
+ CHECK(value_equal(status3, nodeid2, "startphase", "0"));
+ CHECK(value_equal(status3, nodeid2, "dynamic_id", "0"));
+ CHECK(value_equal(status3, nodeid2, "node_group", "0"));
+ CHECK(value_equal(status3, nodeid2, "connect_count", "0"));
+
+ return NDBT_OK;
+
+}
+
NDBT_TESTSUITE(testMgmd);
DRIVER(DummyDriver); /* turn off use of NdbApi */
@@ -981,6 +1146,11 @@ TESTCASE("Bug56844",
{
INITIALIZER(runBug56844);
}
+TESTCASE("Bug12352191",
+ "Test mgmd status for other mgmd")
+{
+ INITIALIZER(runTestBug12352191);
+}
NDBT_TESTSUITE_END(testMgmd);
=== modified file 'storage/ndb/tools/ndb_dump_frm_data.cpp'
--- a/storage/ndb/tools/ndb_dump_frm_data.cpp 2011-06-14 10:42:04 +0000
+++ b/storage/ndb/tools/ndb_dump_frm_data.cpp 2011-06-22 07:57:40 +0000
@@ -20,7 +20,6 @@
#include <NdbApi.hpp>
#include <NDBT.hpp>
-// UNUSED static int oi = 1000;
static struct my_option
my_long_options[] =
{
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-5.1-telco-7.0-spj-scan-vs-scan branch(ole.john.aske:3512 to 3513) | Ole John Aske | 23 Jun |