From 718244e1319e11c22330b444c90ba09bc82de741 Mon Sep 17 00:00:00 2001 From: John David Duncan Date: Tue, 6 Dec 2016 08:31:12 -0800 Subject: [PATCH] wl#9819 patch #3: Declare & implement ProcessInfo and OwnProcessInfo --- storage/ndb/include/kernel/OwnProcessInfo.hpp | 30 +++ storage/ndb/include/kernel/ProcessInfo.hpp | 94 +++++++++ storage/ndb/src/common/util/CMakeLists.txt | 2 + .../ndb/src/common/util/OwnProcessInfo.cpp | 134 ++++++++++++ storage/ndb/src/common/util/ProcessInfo.cpp | 191 ++++++++++++++++++ 5 files changed, 451 insertions(+) create mode 100644 storage/ndb/include/kernel/OwnProcessInfo.hpp create mode 100644 storage/ndb/include/kernel/ProcessInfo.hpp create mode 100644 storage/ndb/src/common/util/OwnProcessInfo.cpp create mode 100644 storage/ndb/src/common/util/ProcessInfo.cpp diff --git a/storage/ndb/include/kernel/OwnProcessInfo.hpp b/storage/ndb/include/kernel/OwnProcessInfo.hpp new file mode 100644 index 000000000000..09c76d5ed65b --- /dev/null +++ b/storage/ndb/include/kernel/OwnProcessInfo.hpp @@ -0,0 +1,30 @@ +/* + Copyright (c) 2016, 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 NDB_OWNPROCESSINFO_HPP +#define NDB_OWNPROCESSINFO_HPP + +class ProcessInfo; + +void setOwnProcessInfoName(const char * pathname); +void setOwnProcessInfoAngelPid(Uint32); +void setOwnProcessInfoServerAddress(const struct sockaddr_in *); +void setOwnProcessInfoPort(Uint16); + +ProcessInfo * getOwnProcessInfo(Uint16 nodeId); + +#endif diff --git a/storage/ndb/include/kernel/ProcessInfo.hpp b/storage/ndb/include/kernel/ProcessInfo.hpp new file mode 100644 index 000000000000..bc0ee4d90bac --- /dev/null +++ b/storage/ndb/include/kernel/ProcessInfo.hpp @@ -0,0 +1,94 @@ +/* + Copyright (c) 2016, 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 NDB_PROCESSINFO_HPP +#define NDB_PROCESSINFO_HPP + + +/* Forward Declarations */ +class ProcessInfoRep; + +/* Class ProcessInfo */ +class ProcessInfo { + friend void getNameFromEnvironment(); + friend ProcessInfo * getOwnProcessInfo(Uint16); + +public: + ProcessInfo(); + ~ProcessInfo() {}; + + static ProcessInfo * forNodeId(Uint16); + static void release(ProcessInfo *); + + bool isValid() const; + void invalidate(); + + void setConnectionName(const char *); + void setConnectionName(Uint32 *signal_data); + void setProcessName(const char *); + void setHostAddress(const struct sockaddr *, socklen_t); + void setHostAddress(const struct in_addr *); + void setHostAddress(Uint32 *signal_data); + void setHostAddress(const char *); + void setPid(); + void setAngelPid(Uint32 pid); + void setPort(Uint16); + void setNodeId(Uint16); + const char * getConnectionName() const { return connection_name; }; + const char * getProcessName() const { return process_name; }; + const char * getHostAddress() const; + int getPid() const; + int getAngelPid() const { return angel_process_id; }; + int getPort() const { return application_port; }; + int getNodeId() const { return node_id; }; + + + /* Interface for Qmgr to build ProcessInfo for remote node + from received signal */ + void initializeFromProcessInfoRep(ProcessInfoRep *); + + STATIC_CONST( ConnectionNameLength = 128 ); + STATIC_CONST( ConnectionNameLengthInWords = 32); + STATIC_CONST( ProcessNameLength = 48 ); + STATIC_CONST( AddressStringLength = 48 ); // Long enough for IPv6 + STATIC_CONST( AddressStringLengthInWords = 12); + +// /* Interface for ClusterManager to create signal */ +// void buildProcessInfoReport(ProcessInfoRep *); +// + +private: /* Data Members */ + char connection_name[ConnectionNameLength]; + char host_address[AddressStringLength]; + char process_name[ProcessNameLength]; + Uint32 node_id; + Uint32 process_id; + Uint32 angel_process_id; + Uint32 application_port; +}; // 240 bytes per node + + +inline bool ProcessInfo::isValid() const { + return process_id; +} + +inline const char * ProcessInfo::getHostAddress() const { + return host_address[0] ? host_address : 0; +} + + +#endif diff --git a/storage/ndb/src/common/util/CMakeLists.txt b/storage/ndb/src/common/util/CMakeLists.txt index 7f75b180b852..f8cd4756174e 100644 --- a/storage/ndb/src/common/util/CMakeLists.txt +++ b/storage/ndb/src/common/util/CMakeLists.txt @@ -62,6 +62,8 @@ ADD_CONVENIENCE_LIBRARY(ndbgeneral CharsetMap.cpp CharsetMapImpl.cpp parse_mask.cpp + ProcessInfo.cpp + OwnProcessInfo.cpp ) SET(NDBGENERAL_LIBS ndbtrace ${ZLIB_LIBRARY} mysys mysys_ssl) TARGET_LINK_LIBRARIES(ndbgeneral ${NDBGENERAL_LIBS}) diff --git a/storage/ndb/src/common/util/OwnProcessInfo.cpp b/storage/ndb/src/common/util/OwnProcessInfo.cpp new file mode 100644 index 000000000000..3c76363c9ae3 --- /dev/null +++ b/storage/ndb/src/common/util/OwnProcessInfo.cpp @@ -0,0 +1,134 @@ +/* + Copyright (c) 2016, 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 "ndb_global.h" +#include "ProcessInfo.hpp" +#include "OwnProcessInfo.hpp" +#include +#include + +extern EventLogger * g_eventLogger; +const char * ndb_basename(const char *path); + +extern "C" { + extern const char * my_progname; +} + +/* Static storage; constructor called at process startup by C++ runtime. */ +ProcessInfo singletonInfo; +NdbLockable theApiMutex; + +/* Public API + * + */ +void setOwnProcessInfoName(const char *pathname) +{ + theApiMutex.lock(); + singletonInfo.setProcessName(ndb_basename(pathname)); + theApiMutex.unlock(); +} + +void setOwnProcessInfoAngelPid(Uint32 pid) +{ + theApiMutex.lock(); + singletonInfo.setAngelPid(pid); + theApiMutex.unlock(); +} + +void setOwnProcessInfoServerAddress(const struct sockaddr_in * addr) +{ + theApiMutex.lock(); + singletonInfo.setHostAddress((const struct sockaddr *) addr, sizeof(addr)); + theApiMutex.unlock(); +} + +void setOwnProcessInfoPort(Uint16 port) +{ + theApiMutex.lock(); + singletonInfo.setPort(port); + theApiMutex.unlock(); +} + + +/* Fill in missing parts of ProcessInfo before providing it to QMgr + or ClusterMgr +*/ + +#ifdef WIN32 +#include "psapi.h" + +void getNameFromEnvironment() +{ + HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + FALSE, singletonInfo.getPid()); + GetModuleFileNameEx(handle, 0, singletonInfo.process_name, + singletonInfo.ProcessNameLength); +} +#else +void getNameFromEnvironment() +{ + const char * path = getenv("_"); + if(path) + { + singletonInfo.setProcessName(ndb_basename(path)); + } +} +#endif + + +/* On unix only, if we are not a daemon, and also not a process group leader, + set parent pid as angel pid. +*/ +static Uint32 getParentPidAsAngel() +{ +#ifndef WIN32 + pid_t parent_process_id = getppid(); + if((parent_process_id != 1) && (getpgrp() != singletonInfo.getPid())) + { + return parent_process_id; + } +#endif + return 0; +} + + +/* Public API for QMgr and ClusterMgr. +*/ +ProcessInfo * getOwnProcessInfo(Uint16 nodeId) { + Guard locked(theApiMutex); + if(singletonInfo.process_id == 0) + { + /* Finalize */ + singletonInfo.setPid(); + singletonInfo.node_id = nodeId; + if(singletonInfo.angel_process_id == 0) + singletonInfo.angel_process_id = getParentPidAsAngel(); + if(singletonInfo.process_name[0] == 0) + { + if(my_progname) + singletonInfo.setProcessName(ndb_basename(my_progname)); + else + getNameFromEnvironment(); + } + + g_eventLogger->info("getOwnProcessInfo: pid %d, name %s, addr %s, node %d", + singletonInfo.getPid(), singletonInfo.getProcessName(), + singletonInfo.getHostAddress(), singletonInfo.getNodeId()); + } + + return & singletonInfo; +} diff --git a/storage/ndb/src/common/util/ProcessInfo.cpp b/storage/ndb/src/common/util/ProcessInfo.cpp new file mode 100644 index 000000000000..0a217acb4968 --- /dev/null +++ b/storage/ndb/src/common/util/ProcessInfo.cpp @@ -0,0 +1,191 @@ +/* + Copyright (c) 2016, 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 "ndb_global.h" +#include "NdbHost.h" +#include "ProcessInfo.hpp" +#include "OwnProcessInfo.hpp" +// #include "signaldata/ProcessInfoRep.hpp" +#include "EventLogger.hpp" +#include "ndb_net.h" +#include "ndb_socket.h" +#include "NdbTCP.h" + +extern EventLogger * g_eventLogger; + +/* Utility Functions */ + +static inline bool isUtf8CharMultibyte(char c) { // is any part of multi-byte char + return (c & 0x80); +} + +static inline bool isUtf8CharInitial(char c) { // is first byte of multi-byte char + return ((c & 0xC0) == 0xC0); +} + +static size_t truncateUtf8(const char * string, size_t max_len) { + size_t len = 0; + if(string) { + len = strnlen(string, max_len); + if(len == max_len) { + char c = string[len]; + if(isUtf8CharMultibyte(c)) { + while(! isUtf8CharInitial(c)) { + c = string[--len]; + } + len--; + } + } + } + return len; +} + + +/* Class ProcessInfo */ + + +ProcessInfo::ProcessInfo() +{ + invalidate(); +} + +void ProcessInfo::invalidate() +{ + memset(connection_name, 0, ConnectionNameLength); + memset(host_address, 0, AddressStringLength); + memset(process_name, 0, ProcessNameLength); + node_id = 0; + process_id = 0; + angel_process_id = 0; + application_port = 0; +} + +/* There is one bootstrap OwnProcessInfo per process, + but API nodes need one ProcessInfo per Ndb_cluster_connection. + This named constructor returns OnwProcessInfo for the first + requested node id. For subsequent node ids, it creates a + new ProcessInfo initialized by copying OwnProcessInfo. +*/ +ProcessInfo * ProcessInfo::forNodeId(Uint16 nodeId) +{ + ProcessInfo * process = getOwnProcessInfo(nodeId); + if(process->node_id == nodeId) + return process; + /* Make a copy */ + ProcessInfo * self = new ProcessInfo(); + strncpy(self->host_address, process->host_address, AddressStringLength); + strncpy(self->process_name, process->process_name, ProcessNameLength); + self->node_id = nodeId; // do not copy node id or connection name + self->process_id = process->process_id; + self->angel_process_id = process->angel_process_id; + self->application_port = process->application_port; + return self; +} + +/* Delete a ProcessInfo only if it was new-allocated in ProcessInfo::forNodeId() +*/ +void ProcessInfo::release(ProcessInfo *self) +{ + if((self != 0) && (self != getOwnProcessInfo(0))) + delete self; +} + +void ProcessInfo::setProcessName(const char * name) { + size_t len = truncateUtf8(name, ProcessNameLength); + strncpy(process_name, name, len); + process_name[len] = 0; +} + +void ProcessInfo::setPid() { + process_id = NdbHost_GetProcessId(); +} + +int ProcessInfo::getPid() const { + assert(isValid()); + return process_id; +} + +void ProcessInfo::setConnectionName(const char * name) { + size_t len = truncateUtf8(name, ConnectionNameLength); + strncpy(connection_name, name, len); + connection_name[len] = 0; + g_eventLogger->info("ProcessInfo set connection name: %s", connection_name); +} + +void ProcessInfo::setConnectionName(Uint32 * signal_data) { + memcpy(connection_name, signal_data, ConnectionNameLength); +} + +void ProcessInfo::setHostAddress(const char * address_string) { + if(address_string) { + strncpy(host_address, address_string, AddressStringLength); + } +} + +void ProcessInfo::setHostAddress(Uint32 * signal_data) { + setHostAddress((const char *) signal_data); +} + +void ProcessInfo::setHostAddress(const struct sockaddr * addr, socklen_t len) { + getnameinfo(addr, len, host_address, AddressStringLength, 0, 0, NI_NUMERICHOST); +} + +void ProcessInfo::setHostAddress(const struct in_addr * addr) { + Ndb_inet_ntop(AF_INET, addr, host_address, AddressStringLength); +} + +void ProcessInfo::setAngelPid(Uint32 pid) { + angel_process_id = pid; +} + +void ProcessInfo::setPort(Uint16 port) { + application_port = port; + g_eventLogger->info("ProcessInfo set port: %d", application_port); +} + +void ProcessInfo::setNodeId(Uint16 nodeId) { + node_id = nodeId; +} + +#ifdef FOR_LATER +void ProcessInfo::initializeFromProcessInfoRep(ProcessInfoRep * signal) { + g_eventLogger->info("Received ProcessInfoRep. " + "Node: %d, Port: %d, Name: %s, Pid: %d", + signal->node_id, signal->application_port, + signal->process_name, signal->process_id); + if(isValid()) invalidate(); + setProcessName( (char *) signal->process_name); + process_id = signal->process_id; + angel_process_id = signal->angel_process_id; + application_port = signal->application_port; + node_id = signal->node_id; +} + +void ProcessInfo::buildProcessInfoReport(ProcessInfoRep *signal) { + memcpy(signal->process_name, process_name, ProcessNameLength); + signal->node_id = node_id; + signal->process_id = process_id; + signal->angel_process_id = angel_process_id; + signal->application_port = application_port; + + g_eventLogger->info("Created ProcessInfoRep. " + "Node: %d, Port: %d, Name: %s, Pid: %d", + signal->node_id, signal->application_port, + signal->process_name, signal->process_id); +} +#endif