diff options
Diffstat (limited to 'TAO/orbsvcs')
181 files changed, 23483 insertions, 2929 deletions
diff --git a/TAO/orbsvcs/ImplRepo_Service/Config_Backing_Store.cpp b/TAO/orbsvcs/ImplRepo_Service/Config_Backing_Store.cpp new file mode 100644 index 00000000000..9ab6842d1a6 --- /dev/null +++ b/TAO/orbsvcs/ImplRepo_Service/Config_Backing_Store.cpp @@ -0,0 +1,315 @@ +// $Id$ + +#include "Config_Backing_Store.h" +#include "Server_Info.h" +#include "Activator_Info.h" +#include "utils.h" +#include "ace/OS_NS_unistd.h" + +static const ACE_TCHAR* STARTUP_COMMAND = ACE_TEXT("StartupCommand"); +static const ACE_TCHAR* WORKING_DIR = ACE_TEXT("WorkingDir"); +static const ACE_TCHAR* ENVIRONMENT = ACE_TEXT("Environment"); +static const ACE_TCHAR* ACTIVATION = ACE_TEXT("Activation"); +static const ACE_TCHAR* PARTIAL_IOR = ACE_TEXT("Location"); +static const ACE_TCHAR* IOR = ACE_TEXT("IOR"); +static const ACE_TCHAR* START_LIMIT = ACE_TEXT("StartLimit"); +static const ACE_TCHAR* ACTIVATOR = ACE_TEXT("Activator"); +static const ACE_TCHAR* SERVERS_ROOT_KEY = ACE_TEXT("Servers"); +static const ACE_TCHAR* ACTIVATORS_ROOT_KEY = ACE_TEXT("Activators"); +static const ACE_TCHAR* TOKEN = ACE_TEXT("Token"); +static const ACE_TCHAR* SERVER_ID = ACE_TEXT("ServerId"); +static const ACE_TCHAR* JACORB_SERVER = ACE_TEXT("JacORBServer"); + +#if defined (ACE_WIN32) && !defined (ACE_LACKS_WIN32_REGISTRY) +static const char* WIN32_REG_KEY = "Software\\TAO\\ImplementationRepository"; +#endif + +Config_Backing_Store::Config_Backing_Store (const Options& opts, + CORBA::ORB_ptr orb, + ACE_Configuration& config) +: Locator_Repository (opts, orb), + config_ (config), + status_ (-1) +{ +} + +Config_Backing_Store::~Config_Backing_Store () +{ +} + +void Config_Backing_Store::loadActivators () +{ + ACE_Configuration_Section_Key root; + int err = + config_.open_section (config_.root_section (), ACTIVATORS_ROOT_KEY, 0, root); + if (err == 0) + { + int index = 0; + ACE_TString name; + while (config_.enumerate_sections (root, index, name) == 0) + { + ACE_CString ior; + u_int token; + + ACE_Configuration_Section_Key key; + + // Can't fail, because we're enumerating + config_.open_section (root, name.c_str(), 0, key); + + config_.get_string_value (key, IOR, ior); + config_.get_integer_value (key, TOKEN, token); + + Activator_Info* ai; + ACE_NEW (ai, Activator_Info (name, token, ior)); + + Activator_Info_Ptr info (ai); + activators ().bind (lcase (name), info); + ++index; + } + } +} + +void +Config_Backing_Store::loadServers () +{ + ACE_Configuration_Section_Key root; + int err = + config_.open_section (config_.root_section (), SERVERS_ROOT_KEY, 0, root); + if (err == 0) + { + int index = 0; + ACE_TString name; + while (config_.enumerate_sections (root, index, name) == 0) + { + ACE_CString server_id, cmdline, dir, envstr, partial_ior, ior, aname, jacorbstr; + u_int amodeint = ImplementationRepository::MANUAL; + u_int start_limit; + + ACE_Configuration_Section_Key key; + + // Can't fail, because we're enumerating + config_.open_section (root, name.c_str(), 0, key); + + // Ignore any missing values. Server name is enough on its own. + config_.get_string_value (key, SERVER_ID, server_id); + config_.get_string_value (key, JACORB_SERVER, jacorbstr); + config_.get_string_value (key, ACTIVATOR, aname); + config_.get_string_value (key, STARTUP_COMMAND, cmdline); + config_.get_string_value (key, WORKING_DIR, dir); + config_.get_string_value (key, ENVIRONMENT, envstr); + config_.get_integer_value (key, ACTIVATION, amodeint); + config_.get_string_value (key, PARTIAL_IOR, partial_ior); + config_.get_string_value (key, IOR, ior); + config_.get_integer_value (key, START_LIMIT, start_limit); + + ImplementationRepository::ActivationMode amode = + static_cast <ImplementationRepository::ActivationMode> (amodeint); + + ImplementationRepository::EnvironmentList env_vars = + ImR_Utils::parseEnvList (envstr); + + bool jacorb_server = jacorbstr == "1" ? true : false; + + Server_Info *si; + ACE_NEW (si, + Server_Info (server_id, name, jacorb_server, aname, + cmdline, env_vars, dir, amode, start_limit, + partial_ior, ior)); + Server_Info_Ptr info (si); + servers ().bind (name, info); + ++index; + } + } +} + +int +Config_Backing_Store::persistent_remove (const ACE_CString& name, + bool activator) +{ + const ACE_TCHAR* const key = + (activator ? ACTIVATORS_ROOT_KEY : SERVERS_ROOT_KEY); + return remove (name, key); +} + +int +Config_Backing_Store::remove (const ACE_CString& name, const ACE_TCHAR* key) +{ + ACE_Configuration_Section_Key root; + int err = config_.open_section (config_.root_section (), key, 0, root); + if (err != 0) + { + if (this->opts_.debug () > 9) + { + ACE_DEBUG((LM_INFO, ACE_TEXT ("could not remove %C, already gone!\n"), + name.c_str())); + } + return 0; // Already gone. + } + return config_.remove_section (root, name.c_str(), 1); +} + +static int get_key (ACE_Configuration& cfg, const ACE_CString& name, + const ACE_TCHAR* const sub_section, + ACE_Configuration_Section_Key& key) +{ + ACE_Configuration_Section_Key root; + int err = cfg.open_section (cfg.root_section(), sub_section, 1, root); + if (err != 0) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("Unable to open config section:%s\n"), + sub_section)); + return err; + } + err = cfg.open_section (root, name.c_str (), 1, key); + if (err != 0) + { + ACE_ERROR((LM_ERROR, ACE_TEXT ("Unable to open config section:%C\n"), + name.c_str ())); + } + return err; +} + +int +Config_Backing_Store::persistent_update(const Server_Info_Ptr& info, bool ) +{ + ACE_Configuration_Section_Key key; + int err = get_key(this->config_, info->name, SERVERS_ROOT_KEY, key); + if (err != 0) + { + ACE_ERROR((LM_ERROR, ACE_TEXT ("ERROR: could not get key for %C\n"), + info->name.c_str ())); + return err; + } + + if (this->opts_.debug() > 9) + { + ACE_DEBUG((LM_INFO, ACE_TEXT ("updating %C\n"), info->name.c_str())); + } + ACE_CString envstr = ImR_Utils::envListToString(info->env_vars); + + this->config_.set_string_value (key, SERVER_ID, info->server_id.c_str()); + this->config_.set_string_value (key, JACORB_SERVER, info->jacorb_server ? "1" : "0"); + this->config_.set_string_value (key, ACTIVATOR, info->activator.c_str()); + this->config_.set_string_value (key, STARTUP_COMMAND, info->cmdline.c_str()); + this->config_.set_string_value (key, WORKING_DIR, info->dir.c_str()); + this->config_.set_string_value (key, ENVIRONMENT, envstr); + this->config_.set_integer_value (key, ACTIVATION, info->activation_mode); + this->config_.set_integer_value (key, START_LIMIT, info->start_limit); + this->config_.set_string_value (key, PARTIAL_IOR, info->partial_ior.c_str()); + this->config_.set_string_value (key, IOR, info->ior.c_str()); + + return 0; +} + +int +Config_Backing_Store::persistent_update(const Activator_Info_Ptr& info, bool ) +{ + ACE_Configuration_Section_Key key; + int err = get_key (this->config_, info->name, ACTIVATORS_ROOT_KEY, key); + if (err != 0) + { + ACE_DEBUG((LM_INFO, + ACE_TEXT ("ERROR: could not get key for activator %C\n"), + info->name.c_str ())); + return err; + } + + if (this->opts_.debug() > 9) + { + ACE_DEBUG((LM_INFO, ACE_TEXT ("updating activator %C\n"), + info->name.c_str ())); + } + this->config_.set_integer_value (key, TOKEN, info->token); + this->config_.set_string_value (key, IOR, info->ior.c_str()); + + return 0; +} + +int +Config_Backing_Store::init_repo (PortableServer::POA_ptr ) +{ + if (status_ != 0) + { + if (this->opts_.debug () > 9) + { + ACE_DEBUG ((LM_INFO, ACE_TEXT ("not loading\n"))); + } + return status_; + } + + loadActivators(); + loadServers(); + + return 0; +} + +Heap_Backing_Store::Heap_Backing_Store (const Options& opts, + CORBA::ORB_ptr orb) +: Config_Backing_Store (opts, orb, heap_), + filename_ (opts.persist_file_name()) +{ + if (opts.repository_erase ()) + { + if (this->opts_.debug () > 9) + { + ACE_DEBUG ((LM_INFO, ACE_TEXT ("Heap start clean\n"))); + } + ACE_OS::unlink ( this->filename_.c_str() ); + } + + status_ = heap_.open (this->filename_.c_str()); +} + +Heap_Backing_Store::~Heap_Backing_Store () +{ +} + +const ACE_TCHAR* +Heap_Backing_Store::repo_mode() const +{ + return this->filename_.c_str(); +} + +#if defined (ACE_WIN32) && !defined (ACE_LACKS_WIN32_REGISTRY) +static HKEY setup_registry (const bool start_clean) +{ + if (start_clean) + { + ACE_Configuration_Win32Registry config ( HKEY_LOCAL_MACHINE ); + ACE_Configuration_Section_Key root; + config.open_section (config.root_section(), "Software\\TAO", 0, root); + config.remove_section (root, "ImplementationRepository", 1); + } + + return ACE_Configuration_Win32Registry:: + resolve_key (HKEY_LOCAL_MACHINE, WIN32_REG_KEY); +} +#endif + +Registry_Backing_Store::Registry_Backing_Store(const Options& opts, + CORBA::ORB_ptr orb) +#if defined (ACE_WIN32) && !defined (ACE_LACKS_WIN32_REGISTRY) +: Config_Backing_Store(opts, orb, win32registry_), + win32registry_ (setup_registry (opts.repository_erase())) +#else +: Config_Backing_Store (opts, orb, invalid_config_) +#endif +{ +#if defined (ACE_WIN32) && !defined (ACE_LACKS_WIN32_REGISTRY) + status_ = 0; +#else + ACE_ERROR ((LM_ERROR, ACE_TEXT ("Registry persistence is only ") + ACE_TEXT ("supported on Windows\n"))); + status_ = -1; +#endif +} + +Registry_Backing_Store::~Registry_Backing_Store () +{ +} + +const ACE_TCHAR* +Registry_Backing_Store::repo_mode () const +{ + return ACE_TEXT("Registry"); +} diff --git a/TAO/orbsvcs/ImplRepo_Service/Config_Backing_Store.h b/TAO/orbsvcs/ImplRepo_Service/Config_Backing_Store.h new file mode 100644 index 00000000000..9044436c20b --- /dev/null +++ b/TAO/orbsvcs/ImplRepo_Service/Config_Backing_Store.h @@ -0,0 +1,125 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** +* @file Config_Backing_Store.h +* +* $Id$ +* +* These classes define ACE_Configuration implementations of the backing store. +* +* @author Darrell Brunsch <brunsch@cs.wustl.edu> +* @author Priyanka Gontla <gontla_p@ociweb.com> +*/ +//============================================================================= + +#ifndef CONFIG_BACKING_STORE_H +#define CONFIG_BACKING_STORE_H + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "Locator_Repository.h" + +class ACE_Configuration; + +/** +* @class Config_Backing_Store +* +* @brief ACE_Configuration backing store interface containing all ImR persistent +* information. +* +*/ +class Config_Backing_Store : public Locator_Repository +{ +public: + Config_Backing_Store(const Options& opts, + CORBA::ORB_ptr orb, + ACE_Configuration& config); + + virtual ~Config_Backing_Store(); + +protected: + /// perform config backing store specific initialization + /// (loads servers and activators from the backing store) + virtual int init_repo(PortableServer::POA_ptr imr_poa); + + /// perform server persistent update + virtual int persistent_update(const Server_Info_Ptr& info, bool add); + + /// perform activator persistent update + virtual int persistent_update(const Activator_Info_Ptr& info, bool add); + + /// perform persistent remove + virtual int persistent_remove(const ACE_CString& name, bool activator); + + /// remove the section with the given name from the key section + int remove(const ACE_CString& name, const ACE_TCHAR* key); + + /// the ACE_Configuration backing store + ACE_Configuration& config_; + /// the status of the config_ + int status_; + +private: + /// load all servers + void loadServers(); + /// load all activators + void loadActivators(); +}; + +/** +* @class Heap_Backing_Store +* +* @brief Heap file backing store containing all ImR persistent information. +* +*/ +class Heap_Backing_Store : public Config_Backing_Store +{ +public: + Heap_Backing_Store(const Options& opts, + CORBA::ORB_ptr orb); + + virtual ~Heap_Backing_Store(); + + /// indicate the Heap filename as the persistence mode for the repository + virtual const ACE_TCHAR* repo_mode() const; + +private: + /// the Heap filename + const ACE_TString filename_; + /// the Heap used for the actual backing store + ACE_Configuration_Heap heap_; +}; + +/** +* @class Registry_Backing_Store +* +* @brief Win32 registry backing store containing all ImR persistent +* information. +* +*/ +class Registry_Backing_Store : public Config_Backing_Store +{ +public: + Registry_Backing_Store(const Options& opts, + CORBA::ORB_ptr orb); + + virtual ~Registry_Backing_Store(); + + /// indicate Registry as the persistence mode for the repository + virtual const ACE_TCHAR* repo_mode() const; + +private: +#if defined (ACE_WIN32) && !defined (ACE_LACKS_WIN32_REGISTRY) + /// the Win32 registry used for the actual backing store + ACE_Configuration_Win32Registry win32registry_; +#else + // invalid config (used to simplify #defines) + ACE_Configuration_Heap invalid_config_; +#endif +}; + + +#endif /* CONFIG_BACKING_STORE_H */ diff --git a/TAO/orbsvcs/ImplRepo_Service/INS_Locator.cpp b/TAO/orbsvcs/ImplRepo_Service/INS_Locator.cpp index 6820bc9285f..a364a85db5e 100644 --- a/TAO/orbsvcs/ImplRepo_Service/INS_Locator.cpp +++ b/TAO/orbsvcs/ImplRepo_Service/INS_Locator.cpp @@ -56,10 +56,78 @@ INS_Locator::locate (const char* object_key) } catch (const ImplementationRepository::NotFound&) { + ACE_CString objkey (object_key); + + // check to see if there are more slashes beyond the first one + ssize_t poaidx2 = objkey.rfind ('/'); + ssize_t poaidx1 = objkey.find ('/'); + if (poaidx1 <= 0 || poaidx2 <= 0 || poaidx1 == poaidx2) + { + throw CORBA::TRANSIENT ( + CORBA::SystemException::_tao_minor_code ( + TAO_IMPLREPO_MINOR_CODE, + 0), + CORBA::COMPLETED_NO); + } + + // remove the data field beyond the last delimiter + // which is assumed to be the object id. + ACE_CString key2 = objkey.substring(0, poaidx2); + while (poaidx2 > poaidx1) + { + try + { + if (imr_locator_.debug () > 1) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ImR: Try activating server using <%s>.\n"), + key2.c_str ())); + } + + CORBA::String_var located = + this->imr_locator_.activate_server_by_object (key2.c_str ()); + + ACE_CString tmp = located.in (); + tmp += object_key; + + if (imr_locator_.debug () > 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ImR: Forwarding invocation on <%s> ") + ACE_TEXT ("to <%s>\n"), key2.c_str (), tmp.c_str())); + } + + return CORBA::string_dup (tmp.c_str ()); + } + catch (const ImplementationRepository::CannotActivate&) + { + throw CORBA::TRANSIENT ( + CORBA::SystemException::_tao_minor_code ( + TAO_IMPLREPO_MINOR_CODE, + 0), + CORBA::COMPLETED_NO); + } + catch (const ImplementationRepository::NotFound&) + { + poaidx2 = key2.rfind ('/'); + if (poaidx2 > poaidx1) + { + // continue to try again + key2 = key2.substring(0, poaidx2); + continue; + } + else + { + break; + } + } + } // while() + + // No match is found throw CORBA::TRANSIENT ( - CORBA::SystemException::_tao_minor_code ( - TAO_IMPLREPO_MINOR_CODE, - 0), - CORBA::COMPLETED_NO); + CORBA::SystemException::_tao_minor_code ( + TAO_IMPLREPO_MINOR_CODE, + 0), + CORBA::COMPLETED_NO); } } diff --git a/TAO/orbsvcs/ImplRepo_Service/ImR_Activator_i.cpp b/TAO/orbsvcs/ImplRepo_Service/ImR_Activator_i.cpp index 15d28889e53..ad7f91357c7 100644 --- a/TAO/orbsvcs/ImplRepo_Service/ImR_Activator_i.cpp +++ b/TAO/orbsvcs/ImplRepo_Service/ImR_Activator_i.cpp @@ -76,6 +76,13 @@ ImR_Activator_i::register_with_imr (ImplementationRepository::Activator_ptr acti if (!CORBA::is_nil (locator_.in ())) { + if (this->debug_ > 9) + { + CORBA::String_var ior = orb_->object_to_string (obj.in ()); + ACE_DEBUG((LM_DEBUG, "ImR Activator: ImplRepoService ior=<%s>\n", + ior.in())); + } + this->registration_token_ = locator_->register_activator (name_.c_str (), activator); @@ -84,6 +91,8 @@ ImR_Activator_i::register_with_imr (ImplementationRepository::Activator_ptr acti return; } + else if (this->debug_ > 1) + ACE_DEBUG((LM_DEBUG, "ImR Activator: ImplRepoService not found\n")); } catch (const CORBA::Exception& ex) { @@ -278,12 +287,17 @@ ImR_Activator_i::start_server(const char* name, { if (debug_ > 1) ACE_DEBUG((LM_DEBUG, "ImR Activator: Starting server <%s>...\n", name)); + + ACE_TString cmdline_tstr(ACE_TEXT_CHAR_TO_TCHAR(cmdline)); + size_t cmdline_buf_len = cmdline_tstr.length(); if (debug_ > 1) - ACE_DEBUG((LM_DEBUG, "\tcommand line : <%s>\n\tdirectory : <%s>\n", cmdline, dir)); + ACE_DEBUG((LM_DEBUG, + "\tcommand line : len=%d <%s>\n\tdirectory : <%C>\n", + cmdline_buf_len, cmdline_tstr.c_str(), dir) ); ACE_Process_Options proc_opts ( 1, - ACE_Process_Options::DEFAULT_COMMAND_LINE_BUF_LEN, + cmdline_buf_len + 1, this->env_buf_len_, this->max_env_vars_); proc_opts.command_line (ACE_TEXT_CHAR_TO_TCHAR(cmdline)); proc_opts.working_directory (dir); diff --git a/TAO/orbsvcs/ImplRepo_Service/ImR_Locator.idl b/TAO/orbsvcs/ImplRepo_Service/ImR_Locator.idl index 604081c7c68..c61361b8165 100644 --- a/TAO/orbsvcs/ImplRepo_Service/ImR_Locator.idl +++ b/TAO/orbsvcs/ImplRepo_Service/ImR_Locator.idl @@ -18,5 +18,54 @@ module ImplementationRepository /// process that it had started. void notify_child_death (in string name); }; + + enum UpdateType + { + repo_add, + repo_update, + repo_remove + }; + + typedef long SequenceNum; + + struct ServerUpdate + { + string name; + string server_id; + UpdateType type; + long repo_id; + long repo_type; + SequenceNum seq_num; + }; + + struct ActivatorUpdate + { + string name; + UpdateType type; + long repo_id; + long repo_type; + SequenceNum seq_num; + }; + + exception InvalidPeer + { + string reason; + }; + + interface UpdatePushNotification + { + /// indicate existing server with name was updated + oneway void notify_updated_server(in ServerUpdate server); + + /// indicate existing activator with name was updated + //oneway void notify_updated_activator(in ActivatorUpdate activator); + oneway void notify_updated_activator(in ActivatorUpdate activator); + + /// register peer as replica and indicate sequence number + void register_replica(in UpdatePushNotification peer, + inout string ft_imr_ior, + out SequenceNum seq_num) + raises (InvalidPeer); + }; }; diff --git a/TAO/orbsvcs/ImplRepo_Service/ImR_Locator_i.cpp b/TAO/orbsvcs/ImplRepo_Service/ImR_Locator_i.cpp index b0f1d714109..3946f8bdc11 100644 --- a/TAO/orbsvcs/ImplRepo_Service/ImR_Locator_i.cpp +++ b/TAO/orbsvcs/ImplRepo_Service/ImR_Locator_i.cpp @@ -4,13 +4,13 @@ #include "utils.h" #include "Iterator.h" #include "INS_Locator.h" +#include "Locator_Repository.h" +#include "Config_Backing_Store.h" +#include "Shared_Backing_Store.h" +#include "XML_Backing_Store.h" #include "orbsvcs/Time_Utilities.h" -#include "tao/IORTable/IORTable.h" -#include "tao/PortableServer/PortableServer.h" -#include "tao/ORB_Core.h" -#include "tao/default_ports.h" #include "tao/Messaging/Messaging.h" #include "tao/AnyTypeCode/Any.h" @@ -20,7 +20,8 @@ static const int DEFAULT_START_LIMIT = 1; -static const int PING_RETRY_SCHEDULE[] = {0, 10, 100, 500, 1000, 1000, 1000, 1000, 5000, 5000}; +static const int PING_RETRY_SCHEDULE[] = {0, 10, 100, 500, 1000, 1000, 1000, + 1000, 5000, 5000}; static const ACE_Time_Value DEFAULT_SERVER_TIMEOUT (0, 10 * 1000); // 10ms @@ -107,7 +108,8 @@ ImR_Locator_i::init_with_orb (CORBA::ORB_ptr orb, Options& opts) ACE_ASSERT (! CORBA::is_nil (this->imr_poa_.in ())); waiter_svt_.debug (debug_ > 1); - PortableServer::ObjectId_var id = PortableServer::string_to_ObjectId ("ImR_AsyncStartupWaiter"); + PortableServer::ObjectId_var id = + PortableServer::string_to_ObjectId ("ImR_AsyncStartupWaiter"); this->imr_poa_->activate_object_with_id (id.in (), &waiter_svt_); obj = this->imr_poa_->id_to_reference (id.in ()); if (startup_timeout_ > ACE_Time_Value::zero) @@ -120,56 +122,58 @@ ImR_Locator_i::init_with_orb (CORBA::ORB_ptr orb, Options& opts) this->imr_poa_->activate_object_with_id (id.in (), this); obj = this->imr_poa_->id_to_reference (id.in ()); - CORBA::String_var ior = this->orb_->object_to_string (obj.in ()); + ImplementationRepository::Locator_var locator = + ImplementationRepository::Locator::_narrow (obj.in ()); + ACE_ASSERT(! CORBA::is_nil (locator.in ())); + const CORBA::String_var ior = this->orb_->object_to_string (obj.in ()); + + // create the selected Locator_Repository with backing store + switch (opts.repository_mode()) + { + case Options::REPO_REGISTRY: + { + repository_.reset(new Registry_Backing_Store(opts, orb)); + break; + } + case Options::REPO_HEAP_FILE: + { + repository_.reset(new Heap_Backing_Store(opts, orb)); + break; + } + case Options::REPO_XML_FILE: + { + repository_.reset(new XML_Backing_Store(opts, orb)); + break; + } + case Options::REPO_SHARED_FILES: + { + repository_.reset(new Shared_Backing_Store(opts, orb)); + break; + } + case Options::REPO_NONE: + { + repository_.reset(new No_Backing_Store(opts, orb)); + break; + } + default: + { + bool invalid_rmode_specified = false; + ACE_ASSERT (invalid_rmode_specified); + ACE_UNUSED_ARG (invalid_rmode_specified); + ACE_ERROR_RETURN (( + LM_ERROR, ACE_TEXT ("Repository failed to initialize\n")), -1); + } + } // Register the ImR for use with INS obj = orb->resolve_initial_references ("IORTable"); IORTable::Table_var ior_table = IORTable::Table::_narrow (obj.in ()); ACE_ASSERT (! CORBA::is_nil (ior_table.in ())); - ior_table->bind ("ImplRepoService", ior.in ()); - ior_table->bind ("ImR", ior.in ()); ior_table->set_locator (this->ins_locator_.in ()); - // Set up multicast support (if enabled) - if (opts.multicast ()) - { - ACE_Reactor* reactor = orb->orb_core ()->reactor (); - if (this->setup_multicast (reactor, ior.in ()) != 0) - return -1; - } - - // Initialize the persistent storage. This will load any values that + // initialize the repository. This will load any values that // may have been persisted before. - // The init can return 1 if there is no persistent file yet. In - // that case, we need not do anything for now. - int init_result = - this->repository_.init (opts); - if (init_result == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "Repository failed to initialize\n"), -1); - } - - // Activate the two poa managers - PortableServer::POAManager_var poaman = - this->root_poa_->the_POAManager (); - poaman->activate (); - poaman = this->imr_poa_->the_POAManager (); - poaman->activate (); - - // We write the ior file last so that the tests can know we are ready. - if (opts.ior_filename ().length () > 0) - { - FILE* fp = ACE_OS::fopen (opts.ior_filename ().c_str (), "w"); - if (fp == 0) - { - ACE_ERROR_RETURN ((LM_ERROR, - "ImR: Could not open file: %s\n", opts.ior_filename ().c_str ()), -1); - } - ACE_OS::fprintf (fp, "%s", ior.in ()); - ACE_OS::fclose (fp); - } - - return 0; + return this->repository_->init(this->root_poa_, this->imr_poa_, ior); } int @@ -197,20 +201,21 @@ ImR_Locator_i::run (void) // debug () came out garbled and the read-only string // caused an ACCESS VIOLATION -- Chad Elliott 10/4/2006 ACE_DEBUG ((LM_DEBUG, - "Implementation Repository: Running\n" - "\tPing Interval : %dms\n" - "\tStartup Timeout : %ds\n" - "\tPersistence : %s\n" - "\tMulticast : %C\n", + ACE_TEXT ("Implementation Repository: Running\n") + ACE_TEXT ("\tPing Interval : %dms\n") + ACE_TEXT ("\tStartup Timeout : %ds\n") + ACE_TEXT ("\tPersistence : %s\n") + ACE_TEXT ("\tMulticast : %C\n"), ping_interval_.msec (), startup_timeout_.sec (), - repository_.repo_mode (), - ior_multicast_.reactor () != 0 ? "Enabled" : "Disabled")); + this->repository_->repo_mode (), + (this->repository_->multicast () != 0 ? + "Enabled" : "Disabled"))); ACE_DEBUG ((LM_DEBUG, - "\tDebug : %d\n" - "\tLocked : %C\n\n", + ACE_TEXT ("\tDebug : %d\n") + ACE_TEXT ("\tLocked : %C\n\n"), debug (), - read_only_ ? "True" : "False")); + (read_only_ ? "True" : "False"))); } this->auto_start_servers (); @@ -221,16 +226,18 @@ ImR_Locator_i::run (void) void ImR_Locator_i::shutdown (CORBA::Boolean activators, CORBA::Boolean servers) { - if (servers != 0 && this->repository_.servers ().current_size () > 0) + if (servers != 0 && this->repository_->servers ().current_size () > 0) { // Note : shutdown is oneway, so we can't throw - ACE_ERROR ((LM_ERROR, "ImR: Shutdown of all servers not implemented.\n")); + ACE_ERROR (( + LM_ERROR, + ACE_TEXT ("ImR: Shutdown of all servers not implemented.\n"))); } - if (activators != 0 && this->repository_.activators ().current_size () > 0) + if (activators != 0 && this->repository_->activators ().current_size () > 0) { ACE_Vector<ImplementationRepository::Activator_var> acts; Locator_Repository::AIMap::ENTRY* entry = 0; - Locator_Repository::AIMap::ITERATOR it (this->repository_.activators ()); + Locator_Repository::AIMap::ITERATOR it (this->repository_->activators ()); for (;it.next (entry) != 0; it.advance ()) { Activator_Info_Ptr info = entry->int_id_; @@ -255,13 +262,15 @@ ImR_Locator_i::shutdown (CORBA::Boolean activators, CORBA::Boolean servers) if (debug_ > 1) { ex._tao_print_exception ( - "ImR: shutdown activator"); + ACE_TEXT ("ImR: shutdown activator")); } } } if (debug_ > 0 && shutdown_errs > 0) { - ACE_DEBUG ((LM_DEBUG, "ImR: Some activators could not be shut down.\n")); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Some activators could not be shut down.\n"))); } } // Technically, we should wait for all the activators to unregister, but @@ -281,92 +290,25 @@ ImR_Locator_i::fini (void) try { if (debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR: Shutting down...\n")); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Shutting down...\n"))); - teardown_multicast (); + this->repository_.release(); this->root_poa_->destroy (1, 1); this->orb_->destroy (); if (debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Shut down successfully.\n")); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Shut down successfully.\n"))); } catch (const CORBA::Exception& ex) { - ex._tao_print_exception ("ImR_Locator_i::fini"); + ex._tao_print_exception (ACE_TEXT ("ImR_Locator_i::fini")); throw; } return 0; } -void -ImR_Locator_i::teardown_multicast () -{ - ACE_Reactor* r = ior_multicast_.reactor (); - if (r != 0) { - r->remove_handler (&ior_multicast_, ACE_Event_Handler::READ_MASK); - ior_multicast_.reactor (0); - } -} - -int -ImR_Locator_i::setup_multicast (ACE_Reactor* reactor, const char* ior) -{ - ACE_ASSERT (reactor != 0); - ACE_ASSERT (ior != 0); -#if defined (ACE_HAS_IP_MULTICAST) - - TAO_ORB_Core* core = TAO_ORB_Core_instance (); - // See if the -ORBMulticastDiscoveryEndpoint option was specified. - ACE_CString mde (core->orb_params ()->mcast_discovery_endpoint ()); - - if (mde.length () != 0) - { - if (this->ior_multicast_.init (ior, - mde.c_str (), TAO_SERVICEID_IMPLREPOSERVICE) == -1) - { - return -1; - } - } - else - { - // Port can be specified as param, env var, or default - CORBA::UShort port = - core->orb_params ()->service_port (TAO::MCAST_IMPLREPOSERVICE); - if (port == 0) - { - // Check environment var. for multicast port. - const char* port_number = ACE_OS::getenv ("ImplRepoServicePort"); - - if (port_number != 0) - port = static_cast<CORBA::UShort> (ACE_OS::atoi (port_number)); - } - if (port == 0) - port = TAO_DEFAULT_IMPLREPO_SERVER_REQUEST_PORT; - - if (this->ior_multicast_.init (ior, port, - ACE_DEFAULT_MULTICAST_ADDR, TAO_SERVICEID_IMPLREPOSERVICE) == -1) - { - return -1; - } - } - - // Register event handler for the ior multicast. - if (reactor->register_handler (&this->ior_multicast_, - ACE_Event_Handler::READ_MASK) == -1) - { - if (debug_ >= 1) - ACE_DEBUG ((LM_DEBUG, "ImR: cannot register Event handler\n")); - return -1; - } -#else /* ACE_HAS_IP_MULTICAST*/ - ACE_UNUSED_ARG (reactor); - ACE_UNUSED_ARG (ior); -#endif /* ACE_HAS_IP_MULTICAST*/ - return 0; -} - CORBA::Long ImR_Locator_i::register_activator (const char* aname, ImplementationRepository::Activator_ptr activator) @@ -383,12 +325,13 @@ ImR_Locator_i::register_activator (const char* aname, CORBA::Long token = ACE_OS::gettimeofday ().msec (); - int err = this->repository_.add_activator (aname, token, ior.in (), activator); + int err = this->repository_->add_activator (aname, token, ior.in (), activator); ACE_ASSERT (err == 0); ACE_UNUSED_ARG (err); if (this->debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Activator registered for %C.\n", aname)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Activator registered for %C.\n"), + aname)); return token; } @@ -404,19 +347,27 @@ ImR_Locator_i::unregister_activator (const char* aname, { if (info->token != token && this->debug_ > 0) { - ACE_DEBUG ((LM_DEBUG, "ImR: Ignoring unregister activator:%C. Wrong token.\n", aname)); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Ignoring unregister activator:%C. Wrong token.\n"), + aname)); return; } this->unregister_activator_i (aname); if (this->debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Activator %C unregistered.\n", aname)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Activator %C unregistered.\n"), + aname)); } else { if (this->debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Ignoring unregister activator: %C. Unknown activator.\n", aname)); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Ignoring unregister activator: %C. ") + ACE_TEXT ("Unknown activator.\n"), + aname)); } } @@ -424,7 +375,7 @@ void ImR_Locator_i::unregister_activator_i (const char* aname) { ACE_ASSERT (aname != 0); - int err = this->repository_.remove_activator (aname); + int err = this->repository_->remove_activator (aname); ACE_UNUSED_ARG (err); } @@ -434,23 +385,19 @@ ImR_Locator_i::notify_child_death (const char* name) ACE_ASSERT (name != 0); if (this->debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR: Server has died <%C>.\n", name)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Server has died <%C>.\n"), name)); - Server_Info_Ptr info = this->repository_.get_server (name); + UpdateableServerInfo info(this->repository_.get(), name); if (! info.null ()) { - info->ior = ""; - info->partial_ior = ""; - - int err = this->repository_.update_server (*info); - ACE_ASSERT (err == 0); - ACE_UNUSED_ARG (err); + info.edit()->ior = ""; + info.edit()->partial_ior = ""; } else { if (this->debug_ > 1) ACE_DEBUG ((LM_DEBUG, - "ImR: Failed to find server in repository.\n")); + ACE_TEXT ("ImR: Failed to find server in repository.\n"))); } } @@ -459,7 +406,8 @@ ImR_Locator_i::activate_server (const char* server) { if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, "ImR: Manually activating server <%C>\n", server)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Manually activating server <%C>\n"), + server)); } // This is the version called by tao_imr to activate the server, manually @@ -475,14 +423,24 @@ ImR_Locator_i::activate_server_by_name (const char* name, bool manual_start) // servers unless manual_start=true ACE_ASSERT (name != 0); - Server_Info_Ptr info = this->repository_.get_server (name); + ACE_CString serverKey; + ACE_CString server_id; + bool jacorb_server = false; + parse_id(name, server_id, serverKey, jacorb_server); + UpdateableServerInfo info(this->repository_.get(), serverKey); if (info.null ()) { - ACE_ERROR ((LM_ERROR, "ImR: Cannot find info for server <%C>\n", name)); + ACE_ERROR (( + LM_ERROR, + ACE_TEXT ("ImR: Cannot find info for server <%C>\n"), + name)); throw ImplementationRepository::NotFound (); } - return activate_server_i (*info, manual_start); + //MDM + info.edit()->start_count = 0; + + return activate_server_i (info, manual_start); } char* @@ -495,15 +453,28 @@ ImR_Locator_i::activate_server_by_object (const char* object_name) ACE_CString server_name (object_name); ACE_CString::size_type pos = server_name.find ('/'); if (pos != ACE_CString::npos) - server_name = server_name.substr (pos + 1); - - return activate_server_by_name (server_name.c_str (), false); + { + try + { + return activate_server_by_name (object_name, false); + } + catch (const ImplementationRepository::NotFound&) + { + server_name = server_name.substr (pos + 1); + return activate_server_by_name (server_name.c_str (), false); + } + } + else + { + return activate_server_by_name (server_name.c_str (), false); + } } char* -ImR_Locator_i::activate_server_i (Server_Info& info, bool manual_start) +ImR_Locator_i::activate_server_i (UpdateableServerInfo& info, + bool manual_start) { - if (info.activation_mode == ImplementationRepository::PER_CLIENT) + if (info->activation_mode == ImplementationRepository::PER_CLIENT) { return activate_perclient_server_i (info, manual_start); } @@ -514,146 +485,162 @@ ImR_Locator_i::activate_server_i (Server_Info& info, bool manual_start) { if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, "ImR: Successfully activated <%C> at \n\t%C\n", - info.name.c_str (), info.partial_ior.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Successfully activated <%C> at \n\t%C\n"), + info->name.c_str (), info->partial_ior.c_str ())); } - info.start_count = 0; + info.edit ()->start_count = 0; - waiter_svt_.unblock_all (info.name.c_str ()); + waiter_svt_.unblock_all (info->name.c_str ()); - return CORBA::string_dup (info.partial_ior.c_str ()); + return CORBA::string_dup (info->partial_ior.c_str ()); } - info.reset (); + info.edit()->reset (); - if (! info.starting && info.start_count >= info.start_limit) + if (! info->starting && info->start_count >= info->start_limit) { if (this->debug_ > 0) { ACE_DEBUG ((LM_DEBUG, - "ImR: Cannot Activate <%C>.\n", info.name.c_str ())); + ACE_TEXT ("ImR: Cannot Activate <%C>.\n"), + info->name.c_str ())); } - waiter_svt_.unblock_all (info.name.c_str ()); + waiter_svt_.unblock_all (info->name.c_str ()); throw ImplementationRepository::CannotActivate( - CORBA::string_dup ( - "Cannot start server.")); + "Cannot start server."); } // Note: We already updated info with StartupInfo in server_is_running () ImplementationRepository::StartupInfo_var si = - start_server (info, manual_start, info.waiting_clients); + start_server (info, manual_start, info.edit()->waiting_clients); } } char* -ImR_Locator_i::activate_perclient_server_i (Server_Info info, bool manual_start) +ImR_Locator_i::activate_perclient_server_i (UpdateableServerInfo& shared_info, + bool manual_start) { - Server_Info_Ptr shared_info = this->repository_.get_server (info.name); + // create a copy of shared_info that can be edited without affecting memory + // in the repository + UpdateableServerInfo info (*shared_info); do { ImplementationRepository::StartupInfo* psi = - start_server (info, manual_start, shared_info->waiting_clients); + start_server (info, manual_start, shared_info.edit()->waiting_clients); + // waiting_clients will be updated by each call to start_server + shared_info.update_repo (); if (psi != 0) { ImplementationRepository::StartupInfo_var si = psi; - ACE_ASSERT (info.name == si->name.in ()); - info.partial_ior = si->partial_ior.in (); - info.ior = si->ior.in (); + ACE_ASSERT (info->name == si->name.in ()); + info.edit ()->partial_ior = si->partial_ior.in (); + info.edit ()->ior = si->ior.in (); if (is_alive (info)) { if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, "ImR: Successfully activated <%C> at \n\t%C\n", - info.name.c_str (), info.partial_ior.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Successfully activated <%C> at \n\t%C\n"), + info->name.c_str (), info->partial_ior.c_str ())); } - return CORBA::string_dup (info.partial_ior.c_str ()); + return CORBA::string_dup (info->partial_ior.c_str ()); } - info.reset (); + info.edit()->reset (); } - } while (info.start_count < info.start_limit); + } while (info->start_count < info->start_limit); if (this->debug_ > 0) { - ACE_DEBUG ((LM_DEBUG, - "ImR: Cannot Activate <%C>.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Cannot Activate <%C>.\n"), + info->name.c_str ())); } - throw ImplementationRepository::CannotActivate( - CORBA::string_dup ( - "Cannot start server.")); + throw ImplementationRepository::CannotActivate("Cannot start server."); } ImplementationRepository::StartupInfo* -ImR_Locator_i::start_server (Server_Info& info, bool manual_start, +ImR_Locator_i::start_server (UpdateableServerInfo& info, bool manual_start, int& waiting_clients) { - if (info.activation_mode == ImplementationRepository::MANUAL && ! manual_start) + if (info->activation_mode == ImplementationRepository::MANUAL && ! manual_start) { if (debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Cannot start server <%C>. ActivationMode=MANUAL\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Cannot start server <%C>. ActivationMode=MANUAL\n"), + info->name.c_str ())); + throw ImplementationRepository::CannotActivate( - CORBA::string_dup ( - "Cannot implicitly activate MANUAL server.")); + "Cannot implicitly activate MANUAL server."); } - if (info.cmdline.length () == 0) + if (info->cmdline.length () == 0) { if (debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Cannot start server <%C>." - " No command line.\n", info.name.c_str ())); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Cannot start server <%C>.") + ACE_TEXT (" No command line.\n"), info->name.c_str ())); throw ImplementationRepository::CannotActivate( - CORBA::string_dup ( - "No command line registered for server.")); + "No command line registered for server."); } - Activator_Info_Ptr ainfo = get_activator (info.activator); + Activator_Info_Ptr ainfo = get_activator (info->activator); if (ainfo.null () || CORBA::is_nil (ainfo->activator.in ())) { if (debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Cannot start server <%C>. " - "Activator <%C> not found.\n", info.name.c_str (), info.activator.c_str ())); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Cannot start server <%C>. ") + ACE_TEXT ("Activator <%C> not found.\n"), + info->name.c_str (), info->activator.c_str ())); throw ImplementationRepository::CannotActivate( - CORBA::string_dup ( - "No activator registered for server.")); + "No activator registered for server."); } + ImplementationRepository::StartupInfo_var si; try { ++waiting_clients; if (waiting_clients <= 1 || - info.activation_mode == ImplementationRepository::PER_CLIENT) + info->activation_mode == ImplementationRepository::PER_CLIENT) { - info.starting = true; - ++info.start_count; - ACE_ASSERT (info.start_count <= info.start_limit); + info.edit()->starting = true; + ++(info.edit()->start_count); + ACE_ASSERT (info->start_count <= info->start_limit); if (this->debug_ > 0) { - ACE_DEBUG ((LM_DEBUG, "ImR: Starting server <%C>. Attempt %d/%d.\n", - info.name.c_str (), info.start_count, info.start_limit)); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Starting server <%C>. Attempt %d/%d.\n"), + info->name.c_str (), info->start_count, info->start_limit)); } ainfo->activator->start_server ( - info.name.c_str (), - info.cmdline.c_str (), - info.dir.c_str (), - info.env_vars); + info->name.c_str (), + info->cmdline.c_str (), + info->dir.c_str (), + info->env_vars); } - if (info.partial_ior.length () == 0) + if (info->partial_ior.length () == 0) { if (this->debug_ > 0) { - ACE_DEBUG ((LM_DEBUG, "ImR: Waiting for <%C> to start...\n", info.name.c_str ())); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ImR: Waiting for <%C> to start...\n"), + info->name.c_str ())); } ImplementationRepository::StartupInfo_var si = - waiter_->wait_for_startup (info.name.c_str ()); + waiter_->wait_for_startup (info->name.c_str ()); --waiting_clients; - info.starting = false; + info.edit()->starting = false; return si._retn (); } @@ -661,43 +648,53 @@ ImR_Locator_i::start_server (Server_Info& info, bool manual_start, { if (this->debug_ > 0) { - ACE_DEBUG ((LM_DEBUG, "ImR: <%C> Skipping wait. Already started.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: <%C> Skipping wait. Already started.\n"), + info->name.c_str ())); } --waiting_clients; - info.starting = false; + info.edit()->starting = false; } } catch (const CORBA::TIMEOUT&) { --waiting_clients; - info.starting = false; + info.edit()->starting = false; // We may have connected successfully, because the timeout could occur before // the AsyncStartupWaiter manages to return. In fact, when the ImR is very busy // this is the most likely code path. - if (info.partial_ior.length () == 0) + if (info->partial_ior.length () == 0) { if (debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR : Timeout waiting for <%C> to start.\n", info.name.c_str ())); - info.reset (); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ImR : Timeout waiting for <%C> to start.\n"), + info->name.c_str ())); + info.edit()->reset (); } } catch (const ImplementationRepository::CannotActivate&) { --waiting_clients; - info.starting = false; - info.reset (); + info.edit()->starting = false; + info.edit()->reset (); if (debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Activator cannot start <%C>.\n", info.name.c_str ())); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ImR: Activator cannot start <%C>.\n"), + info->name.c_str ())); } catch (const CORBA::Exception& ex) { --waiting_clients; - info.starting = false; + info.edit()->starting = false; if (debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Unexpected exception while starting <%C>.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Unexpected exception while starting <%C>.\n"), + info->name.c_str ())); if (debug_ > 1) ex._tao_print_exception (""); - info.reset (); + info.edit()->reset (); // Before we reset the activator info, let's see if it's still // there then let's keep it around for a while. @@ -737,7 +734,8 @@ ImR_Locator_i::set_timeout_policy (CORBA::Object_ptr obj, const ACE_Time_Value& CORBA::PolicyList policies (1); policies.length (1); - policies[0] = orb_->create_policy (Messaging::RELATIVE_RT_TIMEOUT_POLICY_TYPE, tmp); + policies[0] = orb_->create_policy (Messaging::RELATIVE_RT_TIMEOUT_POLICY_TYPE, + tmp); ret = obj->_set_policy_overrides (policies, CORBA::ADD_OVERRIDE); @@ -747,7 +745,8 @@ ImR_Locator_i::set_timeout_policy (CORBA::Object_ptr obj, const ACE_Time_Value& { if (this->debug_ > 0) { - ACE_DEBUG ((LM_DEBUG, "ImR: Unable to set timeout policy.\n")); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ImR: Unable to set timeout policy.\n"))); } ret = CORBA::Object::_duplicate (obj); } @@ -755,7 +754,7 @@ ImR_Locator_i::set_timeout_policy (CORBA::Object_ptr obj, const ACE_Time_Value& catch (const CORBA::Exception& ex) { ex._tao_print_exception ( - "ImR_Locator_i::set_timeout_policy ()"); + ACE_TEXT ("ImR_Locator_i::set_timeout_policy ()")); } return ret._retn (); @@ -770,7 +769,11 @@ ImR_Locator_i::add_or_update_server ( if (this->read_only_) { - ACE_DEBUG ((LM_DEBUG, "ImR: Cannot add/update server <%C> due to locked database.\n", server)); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Cannot add/update server <%C> due to locked ") + ACE_TEXT ("database.\n"), + server)); throw CORBA::NO_PERMISSION ( CORBA::SystemException::_tao_minor_code ( TAO_IMPLREPO_MINOR_CODE, @@ -779,7 +782,7 @@ ImR_Locator_i::add_or_update_server ( } if (debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Add/Update server <%C>.\n", server)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Add/Update server <%C>.\n"), server)); int limit = options.start_limit; if (limit < 0) @@ -791,14 +794,19 @@ ImR_Locator_i::add_or_update_server ( limit = 1; } - Server_Info_Ptr info = this->repository_.get_server (server); + ACE_CString serverKey; + ACE_CString server_id; + bool jacorb_server = false; + parse_id(server, server_id, serverKey, jacorb_server); + UpdateableServerInfo info(this->repository_.get(), serverKey); if (info.null ()) { if (this->debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR: Adding server <%C>.\n", server)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Adding server <%C>.\n"), server)); - this->repository_.add_server ("", - server, + this->repository_->add_server ("", + serverKey, + jacorb_server, options.activator.in (), options.command_line.in (), options.environment, @@ -809,30 +817,30 @@ ImR_Locator_i::add_or_update_server ( else { if (this->debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR: Updating server <%C>.\n", server)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Updating server <%C>.\n"), + server)); + + info.edit ()->activator = options.activator.in (); + info.edit ()->cmdline = options.command_line.in (); + info.edit ()->env_vars = options.environment; + info.edit ()->dir = options.working_directory.in (); + info.edit ()->activation_mode = options.activation; + info.edit ()->start_limit = limit; + info.edit ()->start_count = 0; - info->activator = options.activator.in (); - info->cmdline = options.command_line.in (); - info->env_vars = options.environment; - info->dir = options.working_directory.in (); - info->activation_mode = options.activation; - info->start_limit = limit; - info->start_count = 0; - int err = this->repository_.update_server (*info); - ACE_ASSERT (err == 0); - ACE_UNUSED_ARG (err); + info.update_repo(); } if (this->debug_ > 1) { // Note : The info var may be null, so we use options. - ACE_DEBUG ((LM_DEBUG, "ImR: Server: %s\n" - "\tActivator: %s\n" - "\tCommand Line: %s\n" - "\tWorking Directory: %s\n" - "\tActivation: %s\n" - "\tStart Limit: %d\n" - "\n", + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Server: %C\n") + ACE_TEXT ("\tActivator: %C\n") + ACE_TEXT ("\tCommand Line: %C\n") + ACE_TEXT ("\tWorking Directory: %C\n") + ACE_TEXT ("\tActivation: %C\n") + ACE_TEXT ("\tStart Limit: %d\n") + ACE_TEXT ("\n"), server, options.activator.in (), options.command_line.in (), @@ -842,20 +850,47 @@ ImR_Locator_i::add_or_update_server ( )); for (CORBA::ULong i = 0; i < options.environment.length (); ++i) - ACE_DEBUG ((LM_DEBUG, "Environment variable %s=%s\n", + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Environment variable %C=%C\n"), options.environment[i].name.in (), options.environment[i].value.in ())); } } void +ImR_Locator_i::parse_id(const char* id, + ACE_CString& server_id, + ACE_CString& name, + bool& jacorb_server) +{ + const char *pos = ACE_OS::strchr (id, ':'); + if (pos) + { + ACE_CString idstr (id); + server_id = idstr.substr (0, pos - id); + name = idstr.substr (pos - id + 1); + if (server_id == "JACORB") + { + jacorb_server = true; + ssize_t idx = name.find("/"); + server_id = name.substr(0, idx); + } + } + else + { + name = id; + } +} + +void ImR_Locator_i::remove_server (const char* name) { ACE_ASSERT (name != 0); if (this->read_only_) { - ACE_ERROR ((LM_ERROR, - "ImR: Can't remove server <%C> due to locked database.\n", name)); + ACE_ERROR (( + LM_ERROR, + ACE_TEXT ("ImR: Can't remove server <%C> due to locked database.\n"), + name)); throw CORBA::NO_PERMISSION ( CORBA::SystemException::_tao_minor_code ( TAO_IMPLREPO_MINOR_CODE, @@ -867,15 +902,21 @@ ImR_Locator_i::remove_server (const char* name) // be valid, and the actual Server_Info will be destroyed when the last // one goes out of scope. - Server_Info_Ptr info = this->repository_.get_server (name); + ACE_CString serverKey; + ACE_CString server_id; + bool jacorb_server = false; + parse_id(name, server_id, serverKey, jacorb_server); + Server_Info_Ptr info = this->repository_->get_server (serverKey); if (! info.null ()) { - if (this->repository_.remove_server (name) == 0) + if (this->repository_->remove_server (serverKey) == 0) { if (this->debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR: Removing Server <%C>...\n", name)); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ImR: Removing Server <%C>...\n"), + name)); - PortableServer::POA_var poa = findPOA (name); + PortableServer::POA_var poa = findPOA (serverKey.c_str()); if (! CORBA::is_nil (poa.in ())) { bool etherealize = true; @@ -883,13 +924,14 @@ ImR_Locator_i::remove_server (const char* name) poa->destroy (etherealize, wait); } if (this->debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Removed Server <%C>.\n", name)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Removed Server <%C>.\n"), + name)); } } else { ACE_ERROR ((LM_ERROR, - "ImR: Can't remove unknown server <%s>.\n", name)); + ACE_TEXT ("ImR: Can't remove unknown server <%C>.\n"), name)); throw ImplementationRepository::NotFound (); } } @@ -914,43 +956,54 @@ ImR_Locator_i::shutdown_server (const char* server) ACE_ASSERT (server != 0); if (this->debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Shutting down server <%C>.\n", server)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Shutting down server <%C>.\n"), + server)); + + ACE_CString name; + ACE_CString server_id; + bool jacorb_server = false; + parse_id(server, server_id, name, jacorb_server); - Server_Info_Ptr info = this->repository_.get_server (server); + UpdateableServerInfo info(this->repository_.get(), name); if (info.null ()) { - ACE_ERROR ((LM_ERROR, - "ImR: shutdown_server () Cannot find info for server <%C>\n", server)); + ACE_ERROR (( + LM_ERROR, + ACE_TEXT ("ImR: shutdown_server () Cannot find info for server <%C>\n"), + server)); throw ImplementationRepository::NotFound (); } - this->connect_server (*info); + this->connect_server (info); if (CORBA::is_nil (info->server.in ())) { - ACE_ERROR ((LM_ERROR, - "ImR: shutdown_server () Cannot connect to server <%C>\n", server)); + ACE_ERROR (( + LM_ERROR, + ACE_TEXT ("ImR: shutdown_server () Cannot connect to server <%C>\n"), + server)); throw ImplementationRepository::NotFound (); } try { - CORBA::Object_var obj = this->set_timeout_policy (info->server.in (), DEFAULT_SHUTDOWN_TIMEOUT); + CORBA::Object_var obj = this->set_timeout_policy (info->server.in (), + DEFAULT_SHUTDOWN_TIMEOUT); ImplementationRepository::ServerObject_var server = ImplementationRepository::ServerObject::_unchecked_narrow (obj.in ()); server->shutdown (); } catch (const CORBA::TIMEOUT&) { - info->reset (); - int err = this->repository_.update_server (*info); - ACE_ASSERT (err == 0); - ACE_UNUSED_ARG (err); + info.edit ()->reset (); // Note : This is a good thing. It means we didn't waste our time waiting for // the server to finish shutting down. if (this->debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, "ImR: Timeout while waiting for <%C> shutdown.\n", server)); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Timeout while waiting for <%C> shutdown.\n"), + server)); } throw; } @@ -958,17 +1011,16 @@ ImR_Locator_i::shutdown_server (const char* server) { if (this->debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, "ImR: Exception ignored while shutting down <%C>\n", server)); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Exception ignored while shutting down <%C>\n"), + server)); } } // Note : In most cases this has already been done in the server_is_shutting_down () // operation, but it doesn't hurt to update it again. - info->reset (); - - int err = this->repository_.update_server (*info); - ACE_ASSERT (err == 0); - ACE_UNUSED_ARG (err); + info.edit ()->reset (); } void @@ -982,42 +1034,36 @@ ImR_Locator_i::server_is_running (const char* id, ACE_CString server_id; ACE_CString name; - - const char *pos = ACE_OS::strchr (id, ':'); - if (pos) - { - ACE_CString idstr (id); - server_id = idstr.substr (0, pos - id); - name = idstr.substr (pos - id + 1); - } - else - { - name = id; - } + bool jacorb_server = false; + parse_id(id, server_id, name, jacorb_server); if (this->debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Server %C is running at %C.\n", + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Server %C is running at %C.\n"), name.c_str (), partial_ior)); CORBA::String_var ior = orb_->object_to_string (server); if (this->debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR: Server %C callback at %C.\n", + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Server %C callback at %C.\n"), name.c_str (), ior.in ())); if (this->unregister_if_address_reused_) - this->repository_.unregister_if_address_reused (server_id, name, partial_ior); + this->repository_->unregister_if_address_reused (server_id, name, partial_ior); - Server_Info_Ptr info = this->repository_.get_server (name); + UpdateableServerInfo info(this->repository_.get(), name); if (info.null ()) { if (this->debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Auto adding NORMAL server <%C>.\n", name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Auto adding NORMAL server <%C>.\n"), + name.c_str ())); ImplementationRepository::EnvironmentList env (0); - this->repository_.add_server (server_id, + this->repository_->add_server (server_id, name, + jacorb_server, "", // no activator "", // no cmdline ImplementationRepository::EnvironmentList (), @@ -1036,19 +1082,18 @@ ImR_Locator_i::server_is_running (const char* id, if (! info->server_id.empty()) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR - WARNING: server \"%C\" changed server id from ") - ACE_TEXT ("\"%C\" to \"%C\" waiting PER_CLIENT clients.\n"), - name.c_str (), info->server_id.c_str (), server_id.c_str ())); - info->server_id = server_id; + ACE_TEXT ("\"%C\" to \"%C\" waiting PER_CLIENT clients.\n"), + name.c_str (), info->server_id.c_str (), server_id.c_str ())); + info.edit ()->server_id = server_id; } if (info->activation_mode != ImplementationRepository::PER_CLIENT) { - info->ior = ior.in (); - info->partial_ior = partial_ior; - info->server = ImplementationRepository::ServerObject::_nil (); // Will connect at first access + info.edit ()->ior = ior.in (); + info.edit ()->partial_ior = partial_ior; + // Will connect at first access + info.edit ()->server = ImplementationRepository::ServerObject::_nil (); - int err = this->repository_.update_server (*info); - ACE_ASSERT (err == 0); - ACE_UNUSED_ARG (err); + info.update_repo(); waiter_svt_.unblock_one (name.c_str (), partial_ior, ior.in (), false); } else { @@ -1072,25 +1117,25 @@ void ImR_Locator_i::server_is_shutting_down (const char* server) { ACE_ASSERT (server != 0); - Server_Info_Ptr info = this->repository_.get_server (server); + UpdateableServerInfo info(this->repository_.get(), server); if (info.null ()) { if (this->debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, - "ImR_Locator_i::server_is_shutting_down: Unknown server:%C\n", server)); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR_Locator_i::server_is_shutting_down: ") + ACE_TEXT ("Unknown server:%C\n"), + server)); } return; } if (this->debug_ > 0) - ACE_DEBUG ((LM_DEBUG, "ImR: Server <%C> is shutting down.\n", server)); - - info->reset (); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Server <%C> is shutting down.\n"), + server)); - int const err = this->repository_.update_server (*info); - ACE_ASSERT (err == 0); - ACE_UNUSED_ARG (err); + info.edit ()->reset (); } void @@ -1099,42 +1144,49 @@ ImR_Locator_i::find (const char* server, { ACE_ASSERT (server != 0); - Server_Info_Ptr info = this->repository_.get_server (server); + ACE_CString serverKey; + ACE_CString server_id; + bool jacorb_server = false; + parse_id(server, server_id, serverKey, jacorb_server); + UpdateableServerInfo info(this->repository_.get(), serverKey); if (! info.null ()) { imr_info = info->createImRServerInfo (); if (this->debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR: Found server %C.\n", server)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Found server %C.\n"), server)); } else { - ACE_NEW_THROW_EX (imr_info, ImplementationRepository::ServerInformation, CORBA::NO_MEMORY ()); + ACE_NEW_THROW_EX (imr_info, ImplementationRepository::ServerInformation, + CORBA::NO_MEMORY ()); imr_info->startup.activation= ImplementationRepository::NORMAL; if (this->debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR: Cannot find server <%C>\n", server)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: Cannot find server <%C>\n"), + server)); } } void ImR_Locator_i::list (CORBA::ULong how_many, - ImplementationRepository::ServerInformationList_out server_list, - ImplementationRepository::ServerInformationIterator_out server_iterator) + ImplementationRepository::ServerInformationList_out server_list, + ImplementationRepository::ServerInformationIterator_out server_iterator) { if (this->debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR: List servers.\n")); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ImR: List servers.\n"))); // Initialize the out variables, so if we return early, they will // not be dangling. server_iterator = ImplementationRepository::ServerInformationIterator::_nil (); ACE_NEW_THROW_EX (server_list, - ImplementationRepository::ServerInformationList (0), CORBA::NO_MEMORY ()); + ImplementationRepository::ServerInformationList (0), + CORBA::NO_MEMORY ()); Locator_Repository::SIMap::ENTRY* entry = 0; - Locator_Repository::SIMap::ITERATOR it (this->repository_.servers ()); + Locator_Repository::SIMap::ITERATOR it (this->repository_->servers ()); // Number of servers that will go into the server_list. - CORBA::ULong n = this->repository_.servers ().current_size (); + CORBA::ULong n = this->repository_->servers ().current_size (); if (how_many > 0 && n > how_many) { n = how_many; @@ -1143,7 +1195,10 @@ ImR_Locator_i::list (CORBA::ULong how_many, server_list->length (n); if (this->debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR_Locator_i::list: Filling ServerList with %d servers\n", n)); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR_Locator_i::list: Filling ServerList with %d servers\n"), + n)); for (CORBA::ULong i = 0; i < n; i++) { @@ -1151,22 +1206,27 @@ ImR_Locator_i::list (CORBA::ULong how_many, it.advance (); ACE_ASSERT (entry != 0); - Server_Info_Ptr info = entry->int_id_; + const Server_Info& info = *(entry->int_id_); - ImplementationRepository::ServerInformation_var imr_info = info->createImRServerInfo (); + ImplementationRepository::ServerInformation_var imr_info = + info.createImRServerInfo (); server_list[i] = *imr_info; } - if (this->repository_.servers ().current_size () > n) + if (this->repository_->servers ().current_size () > n) { if (this->debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR_Locator_i::list: Creating ServerInformation Iterator\n")); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR_Locator_i::list: Creating ServerInformation ") + ACE_TEXT ("Iterator\n"))); ImR_Iterator* imr_iter = 0; - ACE_NEW_THROW_EX (imr_iter, - ImR_Iterator (n, this->repository_, this->imr_poa_.in ()), - CORBA::NO_MEMORY ()); + ACE_NEW_THROW_EX ( + imr_iter, + ImR_Iterator (n, *this->repository_, this->imr_poa_.in ()), + CORBA::NO_MEMORY ()); PortableServer::ServantBase_var tmp (imr_iter); @@ -1188,7 +1248,7 @@ ImR_Locator_i::list (CORBA::ULong how_many, Activator_Info_Ptr ImR_Locator_i::get_activator (const ACE_CString& aname) { - Activator_Info_Ptr info = this->repository_.get_activator (aname); + Activator_Info_Ptr info = this->repository_->get_activator (aname); if (! info.null ()) { this->connect_activator (*info); @@ -1228,7 +1288,10 @@ ImR_Locator_i::connect_activator (Activator_Info& info) } if (debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR: Connected to activator <%C>\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Connected to activator <%C>\n"), + info.name.c_str ())); } catch (const CORBA::Exception&) { @@ -1239,18 +1302,18 @@ ImR_Locator_i::connect_activator (Activator_Info& info) void ImR_Locator_i::auto_start_servers (void) { - if (this->repository_.servers ().current_size () == 0) + if (this->repository_->servers ().current_size () == 0) return; Locator_Repository::SIMap::ENTRY* server_entry; - Locator_Repository::SIMap::ITERATOR server_iter (this->repository_.servers ()); + Locator_Repository::SIMap::ITERATOR server_iter (this->repository_->servers ()); // For each of the entries in the Locator_Repository, get the startup // information and activate the servers, if they are not already // running. for (;server_iter.next (server_entry) != 0; server_iter.advance ()) { - Server_Info_Ptr info = server_entry->int_id_; + UpdateableServerInfo info(this->repository_.get(), server_entry->int_id_); ACE_ASSERT (! info.null ()); try @@ -1259,16 +1322,17 @@ ImR_Locator_i::auto_start_servers (void) && info->cmdline.length () > 0) { CORBA::String_var cleanup = - this->activate_server_i (*info, true); + this->activate_server_i (info, true); } } catch (const CORBA::Exception& ex) { if (this->debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, - "ImR: AUTO_START Could not activate <%C>\n", - server_entry->ext_id_.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: AUTO_START Could not activate <%C>\n"), + server_entry->ext_id_.c_str ())); ex._tao_print_exception ("AUTO_START"); } // Ignore exceptions @@ -1277,51 +1341,53 @@ ImR_Locator_i::auto_start_servers (void) } void -ImR_Locator_i::connect_server (Server_Info& info) +ImR_Locator_i::connect_server (UpdateableServerInfo& info) { - if (! CORBA::is_nil (info.server.in ())) + if (! CORBA::is_nil (info->server.in ())) { return; // already connected } - if (info.ior.length () == 0) + if (info->ior.length () == 0) { - info.reset (); + info.edit ()->reset (); return; // can't connect } try { - CORBA::Object_var obj = orb_->string_to_object (info.ior.c_str ()); + CORBA::Object_var obj = orb_->string_to_object (info->ior.c_str ()); if (CORBA::is_nil (obj.in ())) { - info.reset (); + info.edit ()->reset (); return; } obj = this->set_timeout_policy (obj.in (), DEFAULT_SERVER_TIMEOUT); - info.server = + info.edit ()->server = ImplementationRepository::ServerObject::_unchecked_narrow (obj.in ()); - if (CORBA::is_nil (info.server.in ())) + if (CORBA::is_nil (info->server.in ())) { - info.reset (); + info.edit ()->reset (); return; } if (debug_ > 1) - ACE_DEBUG ((LM_DEBUG, "ImR: Connected to server <%C>\n", info.name.c_str ())); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ImR: Connected to server <%C>\n"), + info->name.c_str ())); } catch (const CORBA::Exception&) { - info.reset (); + info.edit ()->reset (); } } bool -ImR_Locator_i::is_alive (Server_Info& info) +ImR_Locator_i::is_alive (UpdateableServerInfo& info) { const size_t table_size = sizeof (PING_RETRY_SCHEDULE) / sizeof (*PING_RETRY_SCHEDULE); @@ -1356,29 +1422,33 @@ ImR_Locator_i::is_alive (Server_Info& info) } if (debug_ > 0) { - ACE_DEBUG ((LM_DEBUG, - "ImR: <%C> Ping retry count exceeded. alive=maybe.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: <%C> Ping retry count exceeded. alive=maybe.\n"), + info->name.c_str ())); } - // We return true here, because the server *might* be alive, it's just not starting in a timely - // manner. We can't return false, because then we'll just try to start another instance, and the - // same thing will likely happen. - info.last_ping = ACE_OS::gettimeofday (); + // We return true here, because the server *might* be alive, it's just + // not starting in a timely manner. We can't return false, because then + // we'll just try to start another instance, and the same thing will + // likely happen. + info.edit ()->last_ping = ACE_OS::gettimeofday (); return true; } int -ImR_Locator_i::is_alive_i (Server_Info& info) +ImR_Locator_i::is_alive_i (UpdateableServerInfo& info) { // This is used by the ACE_TRY below when exceptions are turned off. - if (info.ior.length () == 0 || info.partial_ior.length () == 0) + if (info->ior.length () == 0 || info->partial_ior.length () == 0) { if (debug_ > 1) { ACE_DEBUG ((LM_DEBUG, - "ImR: <%C> not running. alive=false.\n", info.name.c_str ())); + ACE_TEXT ("ImR: <%C> not running. alive=false.\n"), + info->name.c_str ())); } - info.last_ping = ACE_Time_Value::zero; + info.edit ()->last_ping = ACE_Time_Value::zero; return 0; } @@ -1386,18 +1456,22 @@ ImR_Locator_i::is_alive_i (Server_Info& info) { if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, - "ImR: <%C> Ping verification disabled. alive=true.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: <%C> Ping verification disabled. alive=true.\n"), + info->name.c_str ())); } return 1; } - if ((ACE_OS::gettimeofday () - info.last_ping) < ping_interval_) + if ((ACE_OS::gettimeofday () - info->last_ping) < ping_interval_) { if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, - "ImR: <%C> within ping interval. alive=true.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: <%C> within ping interval. alive=true.\n"), + info->name.c_str ())); } return 1; } @@ -1405,24 +1479,28 @@ ImR_Locator_i::is_alive_i (Server_Info& info) // If we don't have enough information to start the server if it isn't already // then we might as well assume it is running. That way the client can get the // status directly from the server. - if (info.cmdline.length () == 0 || ! repository_.has_activator (info.activator)) + if (info->cmdline.length () == 0 || ! repository_->has_activator (info->activator)) { if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, - "ImR: Ping verification skipped. <%C> not startable.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: Ping verification skipped. <%C> not startable.\n"), + info->name.c_str ())); } return 1; } this->connect_server (info); - if (CORBA::is_nil (info.server.in ())) + if (CORBA::is_nil (info->server.in ())) { if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, - "ImR: <%C> Could not connect. alive=false.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: <%C> Could not connect. alive=false.\n"), + info->name.c_str ())); } return 0; } @@ -1430,17 +1508,19 @@ ImR_Locator_i::is_alive_i (Server_Info& info) try { // Make a copy, in case the info is updated during the ping. - ImplementationRepository::ServerObject_var server = info.server; + ImplementationRepository::ServerObject_var server = info->server; // This will timeout if it takes too long server->ping (); if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, - "ImR: <%C> Ping successful. alive=true\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: <%C> Ping successful. alive=true\n"), + info->name.c_str ())); } - info.last_ping = ACE_OS::gettimeofday (); + info.edit ()->last_ping = ACE_OS::gettimeofday (); } catch (const CORBA::TRANSIENT& ex) { @@ -1451,19 +1531,23 @@ ImR_Locator_i::is_alive_i (Server_Info& info) { if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, - "ImR: <%C> Local TRANSIENT. alive=false.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: <%C> Local TRANSIENT. alive=false.\n"), + info->name.c_str ())); } } - info.last_ping = ACE_Time_Value::zero; + info.edit ()->last_ping = ACE_Time_Value::zero; return 0; case TAO_POA_DISCARDING: case TAO_POA_HOLDING: { if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, - "ImR: <%C> Remote TRANSIENT. alive=maybe.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: <%C> Remote TRANSIENT. alive=maybe.\n"), + info->name.c_str ())); } } return -1; // We keep trying to ping, because returning 1 now, would just lead @@ -1473,10 +1557,12 @@ ImR_Locator_i::is_alive_i (Server_Info& info) { if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, - "ImR: <%C> TRANSIENT exception. alive=false.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: <%C> TRANSIENT exception. alive=false.\n"), + info->name.c_str ())); } - info.last_ping = ACE_Time_Value::zero; + info.edit ()->last_ping = ACE_Time_Value::zero; } return 0; } @@ -1487,18 +1573,26 @@ ImR_Locator_i::is_alive_i (Server_Info& info) { if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, - "ImR: <%C> Ping timed out during connection. alive=false.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: <%C> Ping timed out during connection. ") + ACE_TEXT ("alive=false.\n"), + info->name.c_str ())); } - info.last_ping = ACE_Time_Value::zero; - return 0; // still potentially ambiguous, the server could be so busy it couldn't - // even accept a connection. However the more likely assumption is the server is on - // windows, and is dead, but the host ignored the request rather than rejecting it. + info.edit ()->last_ping = ACE_Time_Value::zero; + // still potentially ambiguous, the server could be so busy + // it couldn't even accept a connection. However the more + // likely assumption is the server is on windows, and is dead, + // but the host ignored the request rather than rejecting it. + return 0; } if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, - "ImR: <%C> Ping timed out, maybe completed. alive=true.\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: <%C> Ping timed out, maybe completed. ") + ACE_TEXT ("alive=true.\n"), + info->name.c_str ())); } return 1; // This is "alive" as far as we're concerned. Presumably the client // will have a less stringent timeout policy, or will want to know @@ -1509,10 +1603,13 @@ ImR_Locator_i::is_alive_i (Server_Info& info) { if (debug_ > 1) { - ACE_DEBUG ((LM_DEBUG, "ImR: <%C> Unexpected Ping exception. alive=false\n", info.name.c_str ())); + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT ("ImR: <%C> Unexpected Ping exception. alive=false\n"), + info->name.c_str ())); ex._tao_print_exception ("\n"); } - info.last_ping = ACE_Time_Value::zero; + info.edit ()->last_ping = ACE_Time_Value::zero; return 0; } return 1; diff --git a/TAO/orbsvcs/ImplRepo_Service/ImR_Locator_i.h b/TAO/orbsvcs/ImplRepo_Service/ImR_Locator_i.h index fc26f46433e..ad4a301bfef 100644 --- a/TAO/orbsvcs/ImplRepo_Service/ImR_Locator_i.h +++ b/TAO/orbsvcs/ImplRepo_Service/ImR_Locator_i.h @@ -8,14 +8,14 @@ #include "locator_export.h" #include "Adapter_Activator.h" +#include "Activator_Info.h" #include "Forwarder.h" #include "Locator_Options.h" -#include "Locator_Repository.h" +#include "Server_Info.h" +#include "ace/Auto_Ptr.h" #include "AsyncStartupWaiter_i.h" #include "tao/IORTable/IORTable.h" -#include "orbsvcs/IOR_Multicast.h" - #include "ImR_LocatorS.h" #include "AsyncStartupWaiterS.h" @@ -28,6 +28,8 @@ class ACE_Reactor; ACE_END_VERSIONED_NAMESPACE_DECL class INS_Locator; +class Locator_Repository; +class UpdateableServerInfo; /// Gets a request from a client and depending on the POA name, /// requests an activator to take care of activating the @@ -96,20 +98,19 @@ public: private: - char* activate_server_i (Server_Info& info, bool manual_start); + char* activate_server_i (UpdateableServerInfo& info, + bool manual_start); - char* activate_perclient_server_i (Server_Info info, bool manual_start); + char* activate_perclient_server_i (UpdateableServerInfo& info, + bool manual_start); ImplementationRepository::StartupInfo* - start_server(Server_Info& info, bool manual_start, int& waiting_clients); - - bool is_alive(Server_Info& info); - int is_alive_i(Server_Info& info); + start_server(UpdateableServerInfo& info, + bool manual_start, + int& waiting_clients); - // Set up the multicast related if 'm' is passed on the command - // line. - int setup_multicast (ACE_Reactor *reactor, const char *ior); - void teardown_multicast(); + bool is_alive(UpdateableServerInfo& info); + int is_alive_i(UpdateableServerInfo& info); void unregister_activator_i(const char* activator); @@ -118,11 +119,14 @@ private: void auto_start_servers(void); - CORBA::Object_ptr set_timeout_policy(CORBA::Object_ptr obj, const ACE_Time_Value& to); + CORBA::Object_ptr set_timeout_policy(CORBA::Object_ptr obj, + const ACE_Time_Value& to); - void connect_server(Server_Info& info); + void connect_server(UpdateableServerInfo& info); PortableServer::POA_ptr findPOA(const char* name); + + void parse_id(const char* id, ACE_CString& server_id, ACE_CString& name, bool& jacorb_server); private: // The class that handles the forwarding. @@ -140,9 +144,7 @@ private: int debug_; - TAO_IOR_Multicast ior_multicast_; - - Locator_Repository repository_; + auto_ptr<Locator_Repository> repository_; AsyncStartupWaiter_i waiter_svt_; ImplementationRepository::AsyncStartupWaiter_var waiter_; diff --git a/TAO/orbsvcs/ImplRepo_Service/ImplRepo_Service.mpc b/TAO/orbsvcs/ImplRepo_Service/ImplRepo_Service.mpc index d6deafcb117..881141bd54b 100644 --- a/TAO/orbsvcs/ImplRepo_Service/ImplRepo_Service.mpc +++ b/TAO/orbsvcs/ImplRepo_Service/ImplRepo_Service.mpc @@ -63,7 +63,7 @@ project(ImR_Activator) : orbsvcslib, orbsvcs_output, conv_lib, acexml, avoids_mi } } -project(ImR_Locator) : orbsvcslib, orbsvcs_output, conv_lib, avoids_minimum_corba, avoids_corba_e_compact, avoids_corba_e_micro, iortable, portableserver, messaging, svc_utils, acexml, imr_client { +project(ImR_Locator) : orbsvcslib, orbsvcs_output, conv_lib, avoids_minimum_corba, avoids_corba_e_compact, avoids_corba_e_micro, iortable, portableserver, messaging, svc_utils, acexml, imr_client, iormanip { sharedname = TAO_ImR_Locator dynamicflags += LOCATOR_BUILD_DLL after += ImR_Locator_IDL ImR_Activator_IDL @@ -82,6 +82,9 @@ project(ImR_Locator) : orbsvcslib, orbsvcs_output, conv_lib, avoids_minimum_corb Iterator.cpp Server_Info.cpp Locator_Repository.cpp + Config_Backing_Store.cpp + XML_Backing_Store.cpp + Shared_Backing_Store.cpp } header_files { utils.h @@ -91,7 +94,7 @@ project(ImR_Locator) : orbsvcslib, orbsvcs_output, conv_lib, avoids_minimum_corb } } -project(ImR_Locator_Service) : orbsvcsexe, install, avoids_minimum_corba, avoids_corba_e_compact, avoids_corba_e_micro, iortable, messaging, acexml ,svc_utils, pi_server, imr_client { +project(ImR_Locator_Service) : orbsvcsexe, install_bin, avoids_minimum_corba, avoids_corba_e_compact, avoids_corba_e_micro, iortable, messaging, acexml ,svc_utils, pi_server, imr_client, iormanip { exename = tao_imr_locator after += ImR_Locator ImR_Activator_IDL ImR_Locator_IDL libs += TAO_ImR_Locator TAO_ImR_Activator_IDL TAO_ImR_Locator_IDL diff --git a/TAO/orbsvcs/ImplRepo_Service/Locator_Options.cpp b/TAO/orbsvcs/ImplRepo_Service/Locator_Options.cpp index 8761db1bbaf..265e6bd69ed 100644 --- a/TAO/orbsvcs/ImplRepo_Service/Locator_Options.cpp +++ b/TAO/orbsvcs/ImplRepo_Service/Locator_Options.cpp @@ -29,11 +29,12 @@ Options::Options () , debug_ (1) , multicast_ (false) , service_ (false) -, ping_interval_(DEFAULT_PING_INTERVAL) -, startup_timeout_(DEFAULT_START_TIMEOUT) +, ping_interval_ (DEFAULT_PING_INTERVAL) +, startup_timeout_ (DEFAULT_START_TIMEOUT) , readonly_ (false) -, service_command_(SC_NONE) +, service_command_ (SC_NONE) , unregister_if_address_reused_ (false) +, imr_type_ (STANDALONE_IMR) { } @@ -57,18 +58,21 @@ Options::parse_args (int &argc, ACE_TCHAR *argv[]) } if (ACE_OS::strcasecmp (shifter.get_current (), - ACE_TEXT ("install")) == 0) + ACE_TEXT ("install")) == 0) { this->service_command_ = SC_INSTALL; } else if (ACE_OS::strcasecmp (shifter.get_current (), - ACE_TEXT ("remove")) == 0) + ACE_TEXT ("remove")) == 0) { this->service_command_ = SC_REMOVE; } else { - ACE_ERROR((LM_ERROR, "Error: Unknown service command : %s\n", shifter.get_current())); + ACE_ERROR (( + LM_ERROR, + ACE_TEXT ("Error: Unknown service command : %s\n"), + shifter.get_current ())); this->print_usage (); return -1; } @@ -165,6 +169,38 @@ Options::parse_args (int &argc, ACE_TCHAR *argv[]) this->repo_mode_ = REPO_XML_FILE; } else if (ACE_OS::strcasecmp (shifter.get_current (), + ACE_TEXT ("--primary")) == 0) + { + this->imr_type_ = PRIMARY_IMR; + } + else if (ACE_OS::strcasecmp (shifter.get_current (), + ACE_TEXT ("--backup")) == 0) + { + this->imr_type_ = BACKUP_IMR; + } + else if (ACE_OS::strcasecmp (shifter.get_current (), + ACE_TEXT ("--directory")) == 0) + { + shifter.consume_arg (); + + if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Error: --directory option needs a filename\n"))); + this->print_usage (); + return -1; + } + + this->persist_file_name_ = shifter.get_current (); + this->repo_mode_ = REPO_SHARED_FILES; + + if (this->persist_file_name_.length() && + this->persist_file_name_[this->persist_file_name_.length() - 1] != '/') + { + this->persist_file_name_ += '/'; + } + } + else if (ACE_OS::strcasecmp (shifter.get_current (), ACE_TEXT ("-e")) == 0) { this->erase_repo_ = true; @@ -176,7 +212,8 @@ Options::parse_args (int &argc, ACE_TCHAR *argv[]) if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { - ACE_ERROR ((LM_ERROR, "Error: -t option needs a value\n")); + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Error: -t option needs a value\n"))); this->print_usage (); return -1; } @@ -190,7 +227,8 @@ Options::parse_args (int &argc, ACE_TCHAR *argv[]) if (!shifter.is_anything_left () || shifter.get_current ()[0] == '-') { - ACE_ERROR ((LM_ERROR, "Error: -v option needs a value\n")); + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Error: -v option needs a value\n"))); this->print_usage (); return -1; } @@ -239,20 +277,27 @@ void Options::print_usage (void) const { ACE_ERROR ((LM_ERROR, - "Usage:\n" - "\n" - "ImplRepo_Service [-c cmd] [-d 0|1|2] [-m] [-o file]\n" - " [-r|-p file|-x file] [-s] [-t secs] [-v secs]\n" - " -c command Runs nt service commands ('install' or 'remove')\n" - " -d level Sets the debug level (default 1)\n" - " -l Lock the database\n" - " -m Turn on multicast\n" - " -o file Outputs the ImR's IOR to a file\n" - " -p file Use file for storing/loading settings\n" - " -x file Use XML file for storing/loading setting\n" - " -r Use the registry for storing/loading settings\n" - " -t secs Server startup timeout.(Default=60s)\n" - " -v msecs Server verification interval.(Default=10s)\n" + ACE_TEXT ("Usage:\n") + ACE_TEXT ("\n") + ACE_TEXT ("ImplRepo_Service [-c cmd] [-d 0|1|2] [-e] [-m] [-o file]\n") + ACE_TEXT (" [-r|-p file|-x file|--directory dir [--primary|--backup] ]\n") + ACE_TEXT (" [-s] [-t secs] [-v secs]\n") + ACE_TEXT (" -c command Runs nt service commands ('install' or 'remove')\n") + ACE_TEXT (" -d level Sets the debug level (default 1)\n") + ACE_TEXT (" -e Erase the persisted repository at startup\n") + ACE_TEXT (" -l Lock the database\n") + ACE_TEXT (" -m Turn on multicast\n") + ACE_TEXT (" -o file Outputs the ImR's IOR to a file\n") + ACE_TEXT (" -p file Use file for storing/loading settings\n") + ACE_TEXT (" -x file Use XML file for storing/loading settings\n") + ACE_TEXT (" --directory dir Use individual XML files for storing/loading\n") + ACE_TEXT (" settings in the provided directory\n") + ACE_TEXT (" --primary Replicate the ImplRepo as the primary ImR\n") + ACE_TEXT (" --backup Replicate the ImplRepo as the backup ImR\n") + ACE_TEXT (" -r Use the registry for storing/loading settings\n") + ACE_TEXT (" -s Run as a service\n") + ACE_TEXT (" -t secs Server startup timeout.(Default=60s)\n") + ACE_TEXT (" -v msecs Server verification interval.(Default=10s)\n") )); } @@ -265,7 +310,7 @@ Options::save_registry_options () LONG err = ACE_TEXT_RegCreateKeyEx (SERVICE_REG_ROOT, SERVICE_REG_PATH, 0, - const_cast<ACE_TCHAR*> (ACE_TEXT("")), // class + const_cast<ACE_TCHAR*> (ACE_TEXT ("")), // class REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, @@ -276,47 +321,51 @@ Options::save_registry_options () { return -1; } - err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT("ORBInitOptions"), 0, REG_SZ, + err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("ORBInitOptions"), 0, REG_SZ, (LPBYTE) this->cmdline_.c_str (), this->cmdline_.length () + 1); ACE_ASSERT (err == ERROR_SUCCESS); - err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT("IORFile"), 0, REG_SZ, + err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("IORFile"), 0, REG_SZ, (LPBYTE) ior_output_file_.c_str (), ior_output_file_.length () + 1); ACE_ASSERT (err == ERROR_SUCCESS); - err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT("DebugLevel"), 0, REG_DWORD, + err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("DebugLevel"), 0, REG_DWORD, (LPBYTE) &debug_ , sizeof (debug_)); ACE_ASSERT(err == ERROR_SUCCESS); - err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT("PersistFile"), 0, REG_SZ, + err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("PersistFile"), 0, REG_SZ, (LPBYTE) this->persist_file_name_.c_str (), this->persist_file_name_.length () + 1); ACE_ASSERT (err == ERROR_SUCCESS); DWORD tmp = this->ping_interval_.msec (); - err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT("PingInterval"), 0, REG_DWORD, + err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("PingInterval"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); tmp = this->readonly_ ? 1 : 0; - err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT("Lock"), 0, REG_DWORD, + err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("Lock"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); tmp = this->repo_mode_; - err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT("PersistType"), 0, REG_DWORD, + err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("PersistType"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); tmp = static_cast<DWORD> (this->startup_timeout_.sec()); - err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT("Timeout"), 0, REG_DWORD, + err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("Timeout"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); - tmp = multicast_ ? 1 : 0; - err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT("Multicast"), 0, REG_DWORD, + tmp = this->multicast_ ? 1 : 0; + err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("Multicast"), 0, REG_DWORD, (LPBYTE) &tmp, sizeof (DWORD)); ACE_ASSERT (err == ERROR_SUCCESS); + err = ACE_TEXT_RegSetValueEx (key, ACE_TEXT ("ImrType"), 0, REG_DWORD, + (LPBYTE) &this->imr_type_ , sizeof (this->imr_type_)); + ACE_ASSERT (err == ERROR_SUCCESS); + err = ::RegCloseKey (key); ACE_ASSERT (err == ERROR_SUCCESS); #endif @@ -343,7 +392,7 @@ Options::load_registry_options () ACE_TCHAR tmpstr[4096]; DWORD sz = sizeof (tmpstr); DWORD type = 0; - err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT("ORBInitOptions"), 0, &type, + err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("ORBInitOptions"), 0, &type, (LPBYTE) tmpstr, &sz); if (err == ERROR_SUCCESS) { @@ -353,7 +402,7 @@ Options::load_registry_options () } sz = sizeof(tmpstr); - err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT("IORFile"), 0, &type, + err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("IORFile"), 0, &type, (LPBYTE) tmpstr, &sz); if (err == ERROR_SUCCESS) { @@ -363,7 +412,7 @@ Options::load_registry_options () } sz = sizeof(debug_); - err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT("DebugLevel"), 0, &type, + err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("DebugLevel"), 0, &type, (LPBYTE) &this->debug_ , &sz); if (err == ERROR_SUCCESS) { @@ -372,7 +421,7 @@ Options::load_registry_options () DWORD tmp = 0; sz = sizeof(tmp); - err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT("PingInterval"), 0, &type, + err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("PingInterval"), 0, &type, (LPBYTE) &tmp, &sz); if (err == ERROR_SUCCESS) { @@ -382,7 +431,7 @@ Options::load_registry_options () tmp = 0; sz = sizeof(tmp); - err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT("Lock"), 0, &type, + err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("Lock"), 0, &type, (LPBYTE) &tmp, &sz); if (err == ERROR_SUCCESS) { @@ -391,7 +440,7 @@ Options::load_registry_options () } sz = sizeof(this->repo_mode_); - err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT("PersistType"), 0, &type, + err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("PersistType"), 0, &type, (LPBYTE) &this->repo_mode_, &sz); if (err == ERROR_SUCCESS) { @@ -400,7 +449,7 @@ Options::load_registry_options () tmp = 0; sz = sizeof(tmp); - err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT("Timeout"), 0, &type, + err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("Timeout"), 0, &type, (LPBYTE) &tmp, &sz); if (err == ERROR_SUCCESS) { @@ -410,7 +459,7 @@ Options::load_registry_options () tmp = 0; sz = sizeof(tmp); - err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT("Multicast"), 0, &type, + err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("Multicast"), 0, &type, (LPBYTE) &tmp, &sz); if (err == ERROR_SUCCESS) { @@ -419,7 +468,7 @@ Options::load_registry_options () } sz = sizeof(tmpstr); - err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT("PersistFile"), 0, &type, + err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("PersistFile"), 0, &type, (LPBYTE) tmpstr, &sz); if (err == ERROR_SUCCESS) { @@ -428,6 +477,14 @@ Options::load_registry_options () this->persist_file_name_ = tmpstr; } + sz = sizeof(imr_type_); + err = ACE_TEXT_RegQueryValueEx (key, ACE_TEXT ("ImrType"), 0, &type, + (LPBYTE) &this->imr_type_ , &sz); + if (err == ERROR_SUCCESS) + { + ACE_ASSERT (type == REG_DWORD); + } + err = ::RegCloseKey (key); ACE_ASSERT (err == ERROR_SUCCESS); #endif @@ -509,3 +566,8 @@ Options::unregister_if_address_reused (void) const { return this->unregister_if_address_reused_; } + +Options::ImrType +Options::imr_type(void) const { + return this->imr_type_; +} diff --git a/TAO/orbsvcs/ImplRepo_Service/Locator_Options.h b/TAO/orbsvcs/ImplRepo_Service/Locator_Options.h index 6f041cfdd71..8c62959de12 100644 --- a/TAO/orbsvcs/ImplRepo_Service/Locator_Options.h +++ b/TAO/orbsvcs/ImplRepo_Service/Locator_Options.h @@ -41,13 +41,6 @@ public: SC_REMOVE }; - enum RepoMode { - REPO_NONE, - REPO_XML_FILE, - REPO_HEAP_FILE, - REPO_REGISTRY - }; - Options (); /// Parse the command-line arguments and initialize the options. @@ -81,6 +74,14 @@ public: /// Do we allow modifications to the servers? bool readonly (void) const; + /// Which type of repository is to be used? + enum RepoMode { + REPO_NONE, + REPO_XML_FILE, + REPO_SHARED_FILES, + REPO_HEAP_FILE, + REPO_REGISTRY + }; RepoMode repository_mode (void) const; /// Do we wish to clear out the repository @@ -96,6 +97,10 @@ public: bool unregister_if_address_reused (void) const; + /// Indicate what type of ImR Locator this is. + enum ImrType { BACKUP_IMR, PRIMARY_IMR, STANDALONE_IMR }; + ImrType imr_type(void) const; + private: /// Parses and pulls out arguments for the ImR int parse_args (int &argc, ACE_TCHAR *argv[]); @@ -148,6 +153,9 @@ private: /// Should check the server address and remove previous server if /// the address is reused. bool unregister_if_address_reused_; + + /// The type of ImR Locator this is. + ImrType imr_type_; }; #endif diff --git a/TAO/orbsvcs/ImplRepo_Service/Locator_Repository.cpp b/TAO/orbsvcs/ImplRepo_Service/Locator_Repository.cpp index 5833e0f4e98..9dcc0d4383b 100644 --- a/TAO/orbsvcs/ImplRepo_Service/Locator_Repository.cpp +++ b/TAO/orbsvcs/ImplRepo_Service/Locator_Repository.cpp @@ -1,369 +1,222 @@ // $Id$ #include "Locator_Repository.h" -#include "Locator_XMLHandler.h" #include "utils.h" +#include "tao/ORB_Core.h" +#include "tao/default_ports.h" +#include "ace/Read_Buffer.h" #include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_strings.h" #include "ace/OS_NS_ctype.h" #include "ace/OS_NS_unistd.h" +#include "ace/Vector_T.h" -#include "ACEXML/parser/parser/Parser.h" -#include "ACEXML/common/FileCharStream.h" -#include "ACEXML/common/XML_Util.h" - -static const ACE_TCHAR* STARTUP_COMMAND = ACE_TEXT("StartupCommand"); -static const ACE_TCHAR* WORKING_DIR = ACE_TEXT("WorkingDir"); -static const ACE_TCHAR* ENVIRONMENT = ACE_TEXT("Environment"); -static const ACE_TCHAR* ACTIVATION = ACE_TEXT("Activation"); -static const ACE_TCHAR* PARTIAL_IOR = ACE_TEXT("Location"); -static const ACE_TCHAR* IOR = ACE_TEXT("IOR"); -static const ACE_TCHAR* START_LIMIT = ACE_TEXT("StartLimit"); -static const ACE_TCHAR* ACTIVATOR = ACE_TEXT("Activator"); -static const ACE_TCHAR* SERVERS_ROOT_KEY = ACE_TEXT("Servers"); -static const ACE_TCHAR* ACTIVATORS_ROOT_KEY = ACE_TEXT("Activators"); -static const ACE_TCHAR* TOKEN = ACE_TEXT("Token"); -static const ACE_TCHAR* SERVER_ID = ACE_TEXT("ServerId"); - -#if defined (ACE_WIN32) && !defined (ACE_LACKS_WIN32_REGISTRY) -static const char* WIN32_REG_KEY = "Software\\TAO\\ImplementationRepository"; -#endif - -static ACE_CString lcase (const ACE_CString& s) +Locator_Repository::Locator_Repository (const Options& opts, + CORBA::ORB_ptr orb) +: opts_ (opts), + orb_(CORBA::ORB::_duplicate(orb)), + registered_(false) { - ACE_CString ret(s); - for (size_t i = 0; i < ret.length (); ++i) - { - ret[i] = static_cast<char>(ACE_OS::ace_tolower (s[i])); - } - return ret; } -static void loadActivatorsAsBinary (ACE_Configuration& config, Locator_Repository::AIMap& map) +Locator_Repository::~Locator_Repository () { - ACE_Configuration_Section_Key root; - int err = config.open_section (config.root_section (), ACTIVATORS_ROOT_KEY, 0, root); - if (err == 0) - { - int index = 0; - ACE_TString name; - while (config.enumerate_sections (root, index, name) == 0) - { - ACE_CString ior; - u_int token; - - ACE_Configuration_Section_Key key; - - // Can't fail, because we're enumerating - config.open_section (root, name.c_str(), 0, key); - - config.get_string_value (key, IOR, ior); - config.get_integer_value (key, TOKEN, token); - - Activator_Info_Ptr info (new Activator_Info (name, token, ior)); - map.bind (lcase (name), info); - index++; - } - } + teardown_multicast(); } -static void loadServersAsBinary(ACE_Configuration& config, Locator_Repository::SIMap& map) +int +Locator_Repository::init (PortableServer::POA_ptr root_poa, + PortableServer::POA_ptr imr_poa, + const char* this_ior) { - ACE_Configuration_Section_Key root; - int err = config.open_section (config.root_section (), SERVERS_ROOT_KEY, 0, root); - if (err == 0) + this->imr_ior_ = this_ior; + int err = init_repo(imr_poa); + if (err != 0) { - int index = 0; - ACE_TString name; - while (config.enumerate_sections (root, index, name) == 0) - { - ACE_CString server_id, cmdline, dir, envstr, partial_ior, ior, aname; - u_int amodeint = ImplementationRepository::MANUAL; - u_int start_limit; - - ACE_Configuration_Section_Key key; - - // Can't fail, because we're enumerating - config.open_section (root, name.c_str (), 0, key); - - // Ignore any missing values. Server name is enough on its own. - config.get_string_value (key, SERVER_ID, server_id); - config.get_string_value (key, ACTIVATOR, aname); - config.get_string_value (key, STARTUP_COMMAND, cmdline); - config.get_string_value (key, WORKING_DIR, dir); - config.get_string_value (key, ENVIRONMENT, envstr); - config.get_integer_value(key, ACTIVATION, amodeint); - config.get_string_value (key, PARTIAL_IOR, partial_ior); - config.get_string_value (key, IOR, ior); - config.get_integer_value(key, START_LIMIT, start_limit); - - ImplementationRepository::ActivationMode amode = - static_cast <ImplementationRepository::ActivationMode> (amodeint); - - ImplementationRepository::EnvironmentList env_vars = - ImR_Utils::parseEnvList (envstr); - - Server_Info_Ptr info (new Server_Info(server_id, name, aname, cmdline, - env_vars, dir, amode, start_limit, partial_ior, ior)); - map.bind (name, info); - index++; - } + return err; } -} -static void loadAsBinary (ACE_Configuration& config, Locator_Repository& repo) -{ - loadServersAsBinary (config, repo.servers ()); - loadActivatorsAsBinary (config, repo.activators ()); -} + // Activate the two poa managers + PortableServer::POAManager_var poaman = + root_poa->the_POAManager (); + poaman->activate (); + poaman = imr_poa->the_POAManager (); + poaman->activate (); -// Note : There is no saveAsBinary(), because the ACE_Configuration class -// supports saving of individual entries. + err = report_ior(imr_poa); + return err; +} -static void convertEnvList (const Locator_XMLHandler::EnvList& in, ImplementationRepository::EnvironmentList& out) +int +Locator_Repository::report_ior (PortableServer::POA_ptr ) { - CORBA::ULong sz = in.size (); - out.length (sz); - for (CORBA::ULong i = 0; i < sz; ++i) + if (this->registered_) { - out[i].name = in[i].name.c_str (); - out[i].value = in[i].value.c_str (); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Repository already reported IOR\n")), -1); } -} - -class Server_Repo_XML_Callback : public Locator_XMLHandler::Callback -{ -public: - Server_Repo_XML_Callback(Locator_Repository& repo) - : repo_ (repo) - { - } - virtual void next_server (const ACE_CString& server_id, - const ACE_CString& name, const ACE_CString& aname, - const ACE_CString& cmdline, const Locator_XMLHandler::EnvList& envlst, - const ACE_CString& dir, const ACE_CString& amodestr, int start_limit, - const ACE_CString& partial_ior, const ACE_CString& ior) - { - ImplementationRepository::ActivationMode amode = - ImR_Utils::parseActivationMode (amodestr); - ImplementationRepository::EnvironmentList env_vars; - convertEnvList (envlst, env_vars); - - int limit = start_limit < 1 ? 1 : start_limit; - - Server_Info_Ptr si (new Server_Info (server_id, name, aname, cmdline, - env_vars, dir, amode, limit, partial_ior, ior)); + if (this->opts_.debug () > 0) + { + ACE_DEBUG ((LM_INFO, ACE_TEXT ("report_ior <%C>\n"), + this->imr_ior_.in ())); + } - this->repo_.servers ().bind (name, si); - } - virtual void next_activator (const ACE_CString& aname, - long token, - const ACE_CString& ior) - { - Activator_Info_Ptr si (new Activator_Info (aname, token, ior)); - this->repo_.activators ().bind (lcase (aname), si); - } -private: - Locator_Repository& repo_; -}; + // Register the ImR for use with INS + CORBA::Object_var obj = this->orb_->resolve_initial_references ("IORTable"); + IORTable::Table_var ior_table = IORTable::Table::_narrow (obj.in ()); + ACE_ASSERT (! CORBA::is_nil (ior_table.in ())); -static int loadAsXML (const ACE_CString& fname, Locator_Repository& repo) -{ - ACEXML_FileCharStream* fstm = new ACEXML_FileCharStream; // xml input source will take ownership + ior_table->bind ("ImplRepoService", this->imr_ior_.in()); + ior_table->bind ("ImR", this->imr_ior_.in()); - if (fstm->open (fname.c_str()) != 0) + // Set up multicast support (if enabled) + if (this->opts_.multicast ()) { - // This is not a real error. The xml file may not exist yet. - delete fstm; - return 0; + ACE_Reactor* reactor = this->orb_->orb_core ()->reactor (); + if (this->setup_multicast (reactor, this->imr_ior_.in ()) != 0) + return -1; } - Server_Repo_XML_Callback cb (repo); - - Locator_XMLHandler handler (cb); + // We write the ior file last so that the tests can know we are ready. + if (this->opts_.ior_filename ().length () > 0) + { + FILE* orig_fp = ACE_OS::fopen(this->opts_.ior_filename ().c_str(), + ACE_TEXT("r")); - ACEXML_Parser parser; + bool write_data = true; + if (orig_fp != 0) + { + ACE_Read_Buffer reader (orig_fp, false); - // InputSource takes ownership - ACEXML_InputSource input (fstm); + char* string = reader.read (); - parser.setContentHandler (&handler); - parser.setDTDHandler (&handler); - parser.setErrorHandler (&handler); - parser.setEntityResolver (&handler); + if (string != 0) + { + write_data = + (ACE_OS::strcasecmp (string, this->imr_ior_.in ()) != 0); + reader.alloc ()->free (string); + } + ACE_OS::fclose (orig_fp); + } - try - { - parser.parse (&input); - } - catch (const ACEXML_Exception& ex) - { - ACE_ERROR ((LM_ERROR, "Error during load of ImR persistence xml file.")); - ex.print (); - return -1; + if (write_data) + { + FILE* fp = ACE_OS::fopen (this->opts_.ior_filename ().c_str (), + ACE_TEXT("w")); + if (fp == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("ImR: Could not open file: %s\n"), + this->opts_.ior_filename ().c_str ()), -1); + } + ACE_OS::fprintf (fp, "%s", this->imr_ior_.in ()); + ACE_OS::fclose (fp); + } } + + registered_ = true; + return 0; } -// Note : Would pass servers by const&, but ACE hash map const_iterator is broken. -static void saveAsXML (const ACE_CString& fname, Locator_Repository& repo) +int +Locator_Repository::setup_multicast (ACE_Reactor* reactor, const char* ior) { - FILE* fp = ACE_OS::fopen (fname.c_str (), "w"); - if (fp == 0) + ACE_ASSERT (reactor != 0); +#if defined (ACE_HAS_IP_MULTICAST) + + TAO_ORB_Core* core = TAO_ORB_Core_instance (); + // See if the -ORBMulticastDiscoveryEndpoint option was specified. + ACE_CString mde (core->orb_params ()->mcast_discovery_endpoint ()); + + if (mde.length () != 0) { - ACE_ERROR ((LM_ERROR, "Couldn't write to file %C\n", fname.c_str())); - return; + if (this->ior_multicast_.init (ior, + mde.c_str (), TAO_SERVICEID_IMPLREPOSERVICE) == -1) + { + return -1; + } } - ACE_OS::fprintf (fp,"<?xml version=\"1.0\"?>\n"); - ACE_OS::fprintf (fp,"<%s>\n", Locator_XMLHandler::ROOT_TAG); - - // Save servers - Locator_Repository::SIMap::ENTRY* sientry = 0; - Locator_Repository::SIMap::ITERATOR siit (repo.servers ()); - for (; siit.next (sientry); siit.advance() ) + else { - Server_Info_Ptr& info = sientry->int_id_; - - ACE_CString server_id = ACEXML_escape_string (info->server_id); - ACE_CString name = ACEXML_escape_string (info->name); - ACE_CString activator = ACEXML_escape_string (info->activator); - ACE_CString cmdline = ACEXML_escape_string (info->cmdline); - ACE_CString wdir = ACEXML_escape_string (info->dir); - ACE_CString partial_ior = ACEXML_escape_string (info->partial_ior); - ACE_CString ior = ACEXML_escape_string (info->ior); - - ACE_OS::fprintf (fp,"\t<%s", Locator_XMLHandler::SERVER_INFO_TAG); - ACE_OS::fprintf (fp," server_id=\"%s\"", server_id.c_str ()); - ACE_OS::fprintf (fp," name=\"%s\"", name.c_str ()); - ACE_OS::fprintf (fp," activator=\"%s\"", activator.c_str ()); - ACE_OS::fprintf (fp," command_line=\"%s\"", cmdline.c_str ()); - ACE_OS::fprintf (fp," working_dir=\"%s\"", wdir.c_str ()); - ACE_CString amodestr = ImR_Utils::activationModeToString (info->activation_mode); - ACE_OS::fprintf (fp," activation_mode=\"%s\"", amodestr.c_str ()); - ACE_OS::fprintf (fp," start_limit=\"%d\"", info->start_limit); - ACE_OS::fprintf (fp," partial_ior=\"%s\"", partial_ior.c_str ()); - ACE_OS::fprintf (fp," ior=\"%s\"", ior.c_str ()); - ACE_OS::fprintf (fp,">\n"); - - for (CORBA::ULong i = 0; i < info->env_vars.length (); ++i) + // Port can be specified as param, env var, or default + CORBA::UShort port = + core->orb_params ()->service_port (TAO::MCAST_IMPLREPOSERVICE); + if (port == 0) { - ACE_OS::fprintf (fp,"\t\t<%s", Locator_XMLHandler::ENVIRONMENT_TAG); - ACE_OS::fprintf (fp," name=\"%s\"", info->env_vars[i].name.in ()); - ACE_CString val = ACEXML_escape_string (info->env_vars[i].value.in ()); - ACE_OS::fprintf (fp," value=\"%s\"", val.c_str ()); - ACE_OS::fprintf (fp,"/>\n"); + // Check environment var. for multicast port. + const char* port_number = ACE_OS::getenv ("ImplRepoServicePort"); + + if (port_number != 0) + port = static_cast<CORBA::UShort> (ACE_OS::atoi (port_number)); } + if (port == 0) + port = TAO_DEFAULT_IMPLREPO_SERVER_REQUEST_PORT; - ACE_OS::fprintf (fp,"\t</%s>\n", Locator_XMLHandler::SERVER_INFO_TAG); + if (this->ior_multicast_.init (ior, port, + ACE_DEFAULT_MULTICAST_ADDR, TAO_SERVICEID_IMPLREPOSERVICE) == -1) + { + return -1; + } } - // Save Activators - Locator_Repository::AIMap::ENTRY* aientry = 0; - Locator_Repository::AIMap::ITERATOR aiit (repo.activators ()); - for (; aiit.next (aientry); aiit.advance ()) + // Register event handler for the ior multicast. + if (reactor->register_handler (&this->ior_multicast_, + ACE_Event_Handler::READ_MASK) == -1) { - ACE_CString aname = aientry->ext_id_; - Activator_Info_Ptr& info = aientry->int_id_; - ACE_OS::fprintf (fp,"\t<%s", Locator_XMLHandler::ACTIVATOR_INFO_TAG); - ACE_OS::fprintf( fp," name=\"%s\"", aname.c_str ()); - ACE_OS::fprintf (fp," token=\"%d\"", info->token); - ACE_OS::fprintf (fp," ior=\"%s\"", info->ior.c_str ()); - ACE_OS::fprintf (fp,"/>\n"); + if (this->opts_.debug() > 0) + ACE_DEBUG ((LM_DEBUG, "ImR: cannot register Event handler\n")); + return -1; } - - ACE_OS::fprintf (fp,"</%s>\n", Locator_XMLHandler::ROOT_TAG); - ACE_OS::fclose (fp); +#else /* ACE_HAS_IP_MULTICAST*/ + ACE_UNUSED_ARG (reactor); + ACE_UNUSED_ARG (ior); +#endif /* ACE_HAS_IP_MULTICAST*/ + return 0; } -Locator_Repository::Locator_Repository () -: rmode_ (Options::REPO_NONE) -, config_ (0) -, debug_ (0) +void +Locator_Repository::teardown_multicast () { + ACE_Reactor* r = ior_multicast_.reactor (); + if (r != 0) { + r->remove_handler (&ior_multicast_, ACE_Event_Handler::READ_MASK); + ior_multicast_.reactor (0); + } } -int -Locator_Repository::init(const Options& opts) +bool +Locator_Repository::multicast() const { - this->rmode_ = opts.repository_mode (); - this->fname_ = opts.persist_file_name (); - this->debug_ = opts.debug (); + return this->ior_multicast_.reactor () != 0; +} - int err = 0; - switch (this->rmode_) +ACE_CString +Locator_Repository::lcase (const ACE_CString& s) +{ + ACE_CString ret(s); + for (size_t i = 0; i < ret.length (); ++i) { - case Options::REPO_NONE: - { - break; - } - case Options::REPO_HEAP_FILE: - { - if (opts.repository_erase ()) - { - ACE_OS::unlink ( this->fname_.c_str () ); - } - ACE_Configuration_Heap* heap = new ACE_Configuration_Heap (); - this->config_.reset (heap); - err = heap->open (this->fname_.c_str ()); - if (err == 0) - { - loadAsBinary (*this->config_, *this); - } - break; - } - case Options::REPO_REGISTRY: - { -#if defined (ACE_WIN32) && !defined (ACE_LACKS_WIN32_REGISTRY) - if (opts.repository_erase ()) - { - ACE_Configuration_Win32Registry config ( HKEY_LOCAL_MACHINE ); - ACE_Configuration_Section_Key root; - config.open_section (config.root_section(), "Software\\TAO", 0, root); - config.remove_section (root, "ImplementationRepository", 1); - } - HKEY root = ACE_Configuration_Win32Registry:: - resolve_key (HKEY_LOCAL_MACHINE, WIN32_REG_KEY); - this->config_.reset (new ACE_Configuration_Win32Registry( root)); - loadAsBinary (*this->config_, *this); -#else - ACE_ERROR ((LM_ERROR, "Registry persistence is only " - "supported on Windows\n")); - err = -1; -#endif - break; - } - case Options::REPO_XML_FILE: - { - if (opts.repository_erase ()) - { - ACE_OS::unlink ( this->fname_.c_str() ); - } - err = loadAsXML (this->fname_, *this); - break; - } - default: - { - bool invalid_rmode_specified = false; - ACE_ASSERT (invalid_rmode_specified); - ACE_UNUSED_ARG (invalid_rmode_specified); - err = -1; - } + ret[i] = static_cast<char> (ACE_OS::ace_tolower (s[i])); } - return err; + return ret; } - int Locator_Repository::unregister_if_address_reused ( const ACE_CString& server_id, const ACE_CString& name, const char* partial_ior) { - if (this->debug_ > 0) + if (this->opts_.debug() > 0) { - ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t)ImR: checking reuse address ") + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t)ImR: checking reuse address ") ACE_TEXT ("for server \"%C %C\" ior \"%C\"\n"), - server_id.c_str(), name.c_str (), partial_ior)); + server_id.c_str(), + name.c_str (), + partial_ior)); } ACE_Vector<ACE_CString> srvs; @@ -374,9 +227,10 @@ Locator_Repository::unregister_if_address_reused ( { Server_Info_Ptr& info = sientry->int_id_; - if (this->debug_) + if (this->opts_.debug() > 0) { - ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t)ImR: iterating - registered server") + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t)ImR: iterating - registered server") ACE_TEXT ("\"%C %C\" ior \"%C\"\n"), info->server_id.c_str(), info->name.c_str (), info->partial_ior.c_str ())); } @@ -385,10 +239,11 @@ Locator_Repository::unregister_if_address_reused ( && name != info->name && info->server_id != server_id) { - if (this->debug_) + if (this->opts_.debug() > 0) { - ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t)ImR: reuse address %C so remove") - ACE_TEXT ("server %C \n"), info->partial_ior.c_str (), info->name.c_str ())); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t)ImR: reuse address %C so remove server %C \n"), + info->partial_ior.c_str (), info->name.c_str ())); } if (! info->name.empty ()) { @@ -410,31 +265,38 @@ Locator_Repository::unregister_if_address_reused ( return err; } - - int -Locator_Repository::add_server (const ACE_CString& server_id, - const ACE_CString& name, - const ACE_CString& aname, - const ACE_CString& startup_command, - const ImplementationRepository::EnvironmentList& env_vars, - const ACE_CString& working_dir, - ImplementationRepository::ActivationMode activation, - int start_limit, - const ACE_CString& partial_ior, - const ACE_CString& ior, - ImplementationRepository::ServerObject_ptr svrobj) +Locator_Repository::add_server ( + const ACE_CString& server_id, + const ACE_CString& name, + bool jacorbs, + const ACE_CString& aname, + const ACE_CString& startup_command, + const ImplementationRepository::EnvironmentList& env_vars, + const ACE_CString& working_dir, + ImplementationRepository::ActivationMode activation, + int start_limit, + const ACE_CString& partial_ior, + const ACE_CString& ior, + ImplementationRepository::ServerObject_ptr svrobj) { + int err = sync_load (); + if (err != 0) + { + return err; + } + int limit = start_limit < 1 ? 1 : start_limit; - Server_Info_Ptr info(new Server_Info (server_id, name, aname, startup_command, - env_vars, working_dir, activation, limit, partial_ior, ior, svrobj)); + Server_Info_Ptr info(new Server_Info (server_id, name, jacorbs, aname, + startup_command, env_vars, working_dir, activation, limit, partial_ior, + ior, svrobj)); - int err = servers ().bind (name, info); + err = servers ().bind (name, info); if (err != 0) { return err; } - this->update_server (*info); + this->persistent_update(info, true); return 0; } @@ -444,97 +306,40 @@ Locator_Repository::add_activator (const ACE_CString& name, const ACE_CString& ior, ImplementationRepository::Activator_ptr act) { + int err = sync_load (); + if (err != 0) + { + return err; + } + Activator_Info_Ptr info (new Activator_Info (name, token, ior, act)); - int err = activators ().bind (lcase (name), info); + err = activators ().bind (lcase (name), info); if (err != 0) { return err; } - this->update_activator (*info); + this->persistent_update(info, true); return 0; } int -Locator_Repository::update_server (const Server_Info& info) +Locator_Repository::update_server (const Server_Info_Ptr& info) { - if (rmode_ == Options::REPO_HEAP_FILE || rmode_ == Options::REPO_REGISTRY) - { - ACE_ASSERT (this->config_.get () != 0); - - ACE_Configuration& cfg = *this->config_; - - ACE_Configuration_Section_Key root; - ACE_Configuration_Section_Key key; - int err = cfg.open_section (cfg.root_section(), SERVERS_ROOT_KEY, 1, root); - if (err != 0) - { - ACE_ERROR ((LM_ERROR, "Unable to open config section:%s\n", SERVERS_ROOT_KEY)); - return err; - } - err = cfg.open_section (root, info.name.c_str (), 1, key); - if (err != 0) - { - ACE_ERROR((LM_ERROR, "Unable to open config section:%s\n", info.name.c_str())); - return err; - } - - ACE_CString envstr = ImR_Utils::envListToString(info.env_vars); - - cfg.set_string_value (key, SERVER_ID, info.server_id.c_str ()); - cfg.set_string_value (key, ACTIVATOR, info.activator.c_str ()); - cfg.set_string_value (key, STARTUP_COMMAND, info.cmdline.c_str ()); - cfg.set_string_value (key, WORKING_DIR, info.dir.c_str ()); - cfg.set_string_value (key, ENVIRONMENT, envstr); - cfg.set_integer_value (key, ACTIVATION, info.activation_mode); - cfg.set_integer_value (key, START_LIMIT, info.start_limit); - cfg.set_string_value (key, PARTIAL_IOR, info.partial_ior.c_str ()); - cfg.set_string_value (key, IOR, info.ior.c_str()); - } - else if (rmode_ == Options::REPO_XML_FILE) - { - saveAsXML (this->fname_, *this); - } - return 0; + return this->persistent_update(info, false); } int -Locator_Repository::update_activator (const Activator_Info& info) +Locator_Repository::update_activator (const Activator_Info_Ptr& info) { - if (rmode_ == Options::REPO_HEAP_FILE || rmode_ == Options::REPO_REGISTRY) - { - ACE_ASSERT(this->config_.get () != 0); - - ACE_Configuration& cfg = *this->config_; - - ACE_Configuration_Section_Key root; - ACE_Configuration_Section_Key key; - int err = cfg.open_section (cfg.root_section(), ACTIVATORS_ROOT_KEY, 1, root); - if (err != 0) - { - ACE_ERROR((LM_ERROR, "Unable to open config section:%s\n", ACTIVATORS_ROOT_KEY)); - return err; - } - err = cfg.open_section (root, info.name.c_str (), 1, key); - if (err != 0) - { - ACE_ERROR((LM_ERROR, "Unable to open config section:%s\n", info.name.c_str())); - return err; - } - - cfg.set_integer_value (key, TOKEN, info.token); - cfg.set_string_value (key, IOR, info.ior.c_str ()); - } - else if (rmode_ == Options::REPO_XML_FILE) - { - saveAsXML( this->fname_, *this); - } - return 0; + return this->persistent_update(info, false); } Server_Info_Ptr Locator_Repository::get_server (const ACE_CString& name) { + sync_load (); + Server_Info_Ptr server (0); servers ().find (name, server); return server; @@ -543,6 +348,8 @@ Locator_Repository::get_server (const ACE_CString& name) Activator_Info_Ptr Locator_Repository::get_activator (const ACE_CString& name) { + sync_load (); + Activator_Info_Ptr activator (0); activators ().find (lcase (name), activator); return activator; @@ -558,57 +365,37 @@ Locator_Repository::has_activator (const ACE_CString& name) int Locator_Repository::remove_server (const ACE_CString& name) { + int err = sync_load (); + if (err != 0) + { + return err; + } + int ret = this->servers().unbind (name); if (ret != 0) { return ret; } - if (rmode_ == Options::REPO_HEAP_FILE || rmode_ == Options::REPO_REGISTRY) - { - ACE_ASSERT (this->config_.get() != 0); - ACE_Configuration& cfg = *this->config_; - ACE_Configuration_Section_Key root; - int err = cfg.open_section (cfg.root_section (), SERVERS_ROOT_KEY, 0, root); - if (err != 0) - { - return 0; // Already gone. - } - ret = cfg.remove_section (root, name.c_str (), 1); - } - else if (rmode_ == Options::REPO_XML_FILE) - { - saveAsXML (this->fname_, *this); - } - return ret; + return persistent_remove(name, false); } int Locator_Repository::remove_activator (const ACE_CString& name) { + int err = sync_load (); + if (err != 0) + { + return err; + } + int ret = activators().unbind (lcase(name)); if (ret != 0) { return ret; } - if (rmode_ == Options::REPO_HEAP_FILE || rmode_ == Options::REPO_REGISTRY) - { - ACE_ASSERT (this->config_.get () != 0); - ACE_Configuration& cfg = *this->config_; - ACE_Configuration_Section_Key root; - int err = cfg.open_section (cfg.root_section (), ACTIVATORS_ROOT_KEY, 0, root); - if (err != 0) - { - return 0; // Already gone. - } - ret = cfg.remove_section (root, name.c_str (), 1); - } - else if (rmode_ == Options::REPO_XML_FILE) - { - saveAsXML (this->fname_, *this); - } - return ret; + return persistent_remove(name, true); } Locator_Repository::SIMap& @@ -617,24 +404,150 @@ Locator_Repository::servers (void) return server_infos_; } +const Locator_Repository::SIMap& +Locator_Repository::servers (void) const +{ + return server_infos_; +} + Locator_Repository::AIMap& Locator_Repository::activators (void) { return activator_infos_; } -const char* -Locator_Repository::repo_mode () +const Locator_Repository::AIMap& +Locator_Repository::activators (void) const { - switch (rmode_) - { - case Options::REPO_XML_FILE: - case Options::REPO_HEAP_FILE: - return fname_.c_str (); - case Options::REPO_REGISTRY: - return "Registry"; - case Options::REPO_NONE: - return "Disabled"; - } - return "Disabled"; + return activator_infos_; +} + +int +Locator_Repository::sync_load () +{ + // nothing more to do for default server/activator load + return 0; +} + +bool +Locator_Repository::registered () const +{ + return this->registered_; +} + +UpdateableServerInfo::UpdateableServerInfo ( + Locator_Repository* repo, const ACE_CString& name) +: repo_(repo), + si_(repo->get_server (name)), + needs_update_(false) +{ +} + +UpdateableServerInfo::UpdateableServerInfo (Locator_Repository* repo, + const Server_Info_Ptr& si) +: repo_(repo), + si_(si), + needs_update_(false) +{ +} + +UpdateableServerInfo::UpdateableServerInfo (const Server_Info& si) +: repo_(0), + si_(new Server_Info(si)), + needs_update_(false) +{ +} + +UpdateableServerInfo::~UpdateableServerInfo () +{ + update_repo(); +} + +void +UpdateableServerInfo::update_repo () +{ + if (!needs_update_) + return; + + needs_update_ = false; + int err = repo_->update_server (si_); + ACE_ASSERT (err == 0); + ACE_UNUSED_ARG (err); +} + +const Server_Info* +UpdateableServerInfo::operator-> () const +{ + return si_.get(); +} + +const Server_Info& +UpdateableServerInfo::operator* () const +{ + return *(si_.get()); +} + + +const Server_Info_Ptr& +UpdateableServerInfo::edit () +{ + needs_update_ = repo_ != 0; + return si_; +} + +void +UpdateableServerInfo::needs_update () +{ + needs_update_ = true; +} + +bool +UpdateableServerInfo::null() const +{ + return si_.null(); +} + +No_Backing_Store::No_Backing_Store (const Options& opts, + CORBA::ORB_ptr orb) + : Locator_Repository(opts, orb) +{ +} + +No_Backing_Store::~No_Backing_Store () +{ +} + +const ACE_TCHAR* +No_Backing_Store::repo_mode () const +{ + return ACE_TEXT ("Disabled"); } + +int +No_Backing_Store::init_repo (PortableServer::POA_ptr ) +{ + // nothing more to do for no backing store init + return 0; +} + +int +No_Backing_Store::persistent_update (const Server_Info_Ptr& , bool ) +{ + // nothing more to do for no backing store update + return 0; +} + +int +No_Backing_Store::persistent_update (const Activator_Info_Ptr& , bool ) +{ + // nothing more to do for no backing store update + return 0; +} + +int +No_Backing_Store::persistent_remove (const ACE_CString& , bool ) +{ + // nothing more to do for no backing store remove + return 0; +} + diff --git a/TAO/orbsvcs/ImplRepo_Service/Locator_Repository.h b/TAO/orbsvcs/ImplRepo_Service/Locator_Repository.h index 7d7092769bc..204f1541c70 100644 --- a/TAO/orbsvcs/ImplRepo_Service/Locator_Repository.h +++ b/TAO/orbsvcs/ImplRepo_Service/Locator_Repository.h @@ -20,6 +20,10 @@ #include "Activator_Info.h" #include "Locator_Options.h" +#include "tao/IORTable/IORTable.h" +#include "tao/PortableServer/PortableServer.h" +#include "orbsvcs/IOR_Multicast.h" + #include "ace/Hash_Map_Manager.h" #include "ace/Configuration.h" #include "ace/Auto_Ptr.h" @@ -28,6 +32,8 @@ # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ +class ACE_Reactor; + /** * @class Locator_Repository * @@ -37,22 +43,23 @@ class Locator_Repository { public: - typedef ACE_Hash_Map_Manager_Ex<ACE_CString, + typedef ACE_CString ServerKey; + typedef ACE_Hash_Map_Manager_Ex<ServerKey, Server_Info_Ptr, - ACE_Hash<ACE_CString>, - ACE_Equal_To<ACE_CString>, + ACE_Hash<ServerKey>, + ACE_Equal_To<ServerKey>, ACE_Null_Mutex> SIMap; - typedef ACE_Hash_Map_Manager_Ex<ACE_CString, + typedef ACE_CString ActivatorKey; + typedef ACE_Hash_Map_Manager_Ex<ActivatorKey, Activator_Info_Ptr, - ACE_Hash<ACE_CString>, - ACE_Equal_To<ACE_CString>, + ACE_Hash<ActivatorKey>, + ACE_Equal_To<ActivatorKey>, ACE_Null_Mutex> AIMap; - Locator_Repository(); + Locator_Repository(const Options& opts, CORBA::ORB_ptr orb); - /// Initializes the Server Repository - int init (const Options& opts); + virtual ~Locator_Repository(); int unregister_if_address_reused (const ACE_CString& server_id, const ACE_CString& name, @@ -61,6 +68,7 @@ public: /// Add a new server to the Repository int add_server (const ACE_CString& server_id, const ACE_CString& name, + bool jacorbs, const ACE_CString& aname, const ACE_CString& startup_command, const ImplementationRepository::EnvironmentList& environment_vars, @@ -69,19 +77,21 @@ public: int start_limit, const ACE_CString& partial_ior = ACE_CString(""), const ACE_CString& ior = ACE_CString(""), - ImplementationRepository::ServerObject_ptr svrobj = ImplementationRepository::ServerObject::_nil() + ImplementationRepository::ServerObject_ptr svrobj = + ImplementationRepository::ServerObject::_nil() ); /// Add a new activator to the Repository int add_activator (const ACE_CString& name, const CORBA::Long token, const ACE_CString& ior = ACE_CString(""), - ImplementationRepository::Activator_ptr act = ImplementationRepository::Activator::_nil() + ImplementationRepository::Activator_ptr act = + ImplementationRepository::Activator::_nil() ); /// Update the associated information. - int update_server (const Server_Info& info); + int update_server (const Server_Info_Ptr& info); /// Update the associated information. - int update_activator (const Activator_Info& info); + int update_activator (const Activator_Info_Ptr& info); /// Returns information related to startup. Server_Info_Ptr get_server (const ACE_CString& name); @@ -97,25 +107,154 @@ public: /// Returns the internal hash map containing the server information. SIMap& servers(void); + const SIMap& servers(void) const; /// Returns the internal hash map containing the activator information. AIMap& activators(void); + const AIMap& activators(void) const; + + /// indicate the persistence mode for the repository + virtual const ACE_TCHAR* repo_mode() const = 0; + + /// convert to lower case + static ACE_CString lcase (const ACE_CString& s); + + /// Initialize the repo + int init(PortableServer::POA_ptr root_poa, + PortableServer::POA_ptr imr_poa, + const char* this_ior); + + /// Indicate if multicast should be used + bool multicast() const; + +protected: + /// perform repo mode specific initialization + virtual int init_repo(PortableServer::POA_ptr imr_poa) = 0; + + /// perform sync of repo with backing store + /// defaults to no-op, only shared backing stores + /// need to sync + virtual int sync_load(); + + /// perform server persistent update + virtual int persistent_update(const Server_Info_Ptr& info, bool add) = 0; + + /// perform activator persistent update + virtual int persistent_update(const Activator_Info_Ptr& info, bool add) = 0; + + /// perform persistent remove + virtual int persistent_remove(const ACE_CString& name, bool activator) = 0; + + /// report the ImR Locator's IOR + virtual int report_ior(PortableServer::POA_ptr imr_poa); + + int setup_multicast (ACE_Reactor* reactor, const char* imr_ior); + void teardown_multicast(); - const char* repo_mode(); + bool registered() const; + + const Options& opts_; + TAO_IOR_Multicast ior_multicast_; + const CORBA::ORB_var orb_; + CORBA::String_var imr_ior_; private: - /// Type mechanism to use for persistence. - Options::RepoMode rmode_; + bool registered_; /// The in-memory list of the server information. SIMap server_infos_; /// The in-memory list of the activator information. AIMap activator_infos_; - /// Several rmode_ values require this. - ACE_Auto_Ptr<ACE_Configuration> config_; - /// XML requires the file name - ACE_CString fname_; +}; + +/** +* @class XML_Backing_Store +* +* @brief XML backing store interface containing all ImR persistent information +* in a single file +* +*/ +class No_Backing_Store : public Locator_Repository +{ +public: + No_Backing_Store(const Options& opts, + CORBA::ORB_ptr orb); - unsigned int debug_; + virtual ~No_Backing_Store(); + + /// indicate the persistence mode for the repository + virtual const ACE_TCHAR* repo_mode() const; + +private: + /// perform repo mode specific initialization (no-op) + virtual int init_repo(PortableServer::POA_ptr imr_poa); + + /// perform server persistent update (no-op) + virtual int persistent_update(const Server_Info_Ptr& info, bool add); + + /// perform activator persistent update (no-op) + virtual int persistent_update(const Activator_Info_Ptr& info, bool add); + + /// perform persistent remove (no-op) + virtual int persistent_remove(const ACE_CString& name, bool activator); }; +/** +* @class UpdateableServerInfo +* +* @brief Class for managing changes to ServerInfo memory to ensure +* it is persisted +* +*/ +class UpdateableServerInfo +{ +public: + /// constructor + /// @param repo the repo to report updates to + /// @param name the name of the server to retrieve + UpdateableServerInfo(Locator_Repository* repo, const ACE_CString& name); + + /// constructor + /// @param repo the repo to report updates to + /// @param si an already retrieved Server_Info_Ptr + UpdateableServerInfo(Locator_Repository* repo, const Server_Info_Ptr& si); + + /// constructor (no repo updates will be performed) + /// @param si a Server_Info to create a non-stored Server_Info_Ptr from + UpdateableServerInfo(const Server_Info& si); + + /// destructor (updates repo if needed) + ~UpdateableServerInfo(); + + /// explicitly update repo if needed + void update_repo(); + + /// const Server_Info access + const Server_Info* operator->() const; + + /// const Server_Info& access + const Server_Info& operator*() const; + + /// retrieve smart pointer to non-const Server_Info + /// and indicate repo update required + const Server_Info_Ptr& edit(); + + /// force indication of update needed + void needs_update(); + + /// indicate it Server_Info_Ptr is null + bool null() const; +private: + UpdateableServerInfo(const UpdateableServerInfo& ); + const UpdateableServerInfo& operator=(const UpdateableServerInfo& ); + + /// the repo + Locator_Repository* const repo_; + + /// the retrieved, passed, or non-stored server info + const Server_Info_Ptr si_; + + /// the server info has changes and needs to be updated to the repo + bool needs_update_; +}; + #endif /* REPOSITORY_H */ diff --git a/TAO/orbsvcs/ImplRepo_Service/Locator_XMLHandler.cpp b/TAO/orbsvcs/ImplRepo_Service/Locator_XMLHandler.cpp index cca3d951a82..765edf5deef 100644 --- a/TAO/orbsvcs/ImplRepo_Service/Locator_XMLHandler.cpp +++ b/TAO/orbsvcs/ImplRepo_Service/Locator_XMLHandler.cpp @@ -1,18 +1,39 @@ // $Id$ #include "Locator_XMLHandler.h" +#include "XML_Backing_Store.h" +#include "utils.h" #include "ace/OS_NS_strings.h" +#include "ace/OS_NS_sys_time.h" const ACE_TCHAR* Locator_XMLHandler::ROOT_TAG = ACE_TEXT("ImplementationRepository"); const ACE_TCHAR* Locator_XMLHandler::SERVER_INFO_TAG = ACE_TEXT("Servers"); const ACE_TCHAR* Locator_XMLHandler::ACTIVATOR_INFO_TAG = ACE_TEXT("Activators"); const ACE_TCHAR* Locator_XMLHandler::ENVIRONMENT_TAG = ACE_TEXT("EnvironmentVariables"); -Locator_XMLHandler::Locator_XMLHandler (Callback& cb) -: callback_ (cb) +Locator_XMLHandler::Locator_XMLHandler (XML_Backing_Store& repo, + CORBA::ORB_ptr orb) +: repo_(repo), + start_limit_(0), + server_started_(false), + repo_id_(0), + repo_type_(0), + orb_(CORBA::ORB::_duplicate(orb)) { } +static void convertEnvList (const Locator_XMLHandler::EnvList& in, + ImplementationRepository::EnvironmentList& out) +{ + CORBA::ULong sz = in.size (); + out.length (sz); + for (CORBA::ULong i = 0; i < sz; ++i) + { + out[i].name = in[i].name.c_str (); + out[i].value = in[i].value.c_str (); + } +} + void Locator_XMLHandler::startElement (const ACEXML_Char*, const ACEXML_Char*, @@ -25,31 +46,60 @@ Locator_XMLHandler::startElement (const ACEXML_Char*, // We'll use this as a key to determine if we've got a valid record this->server_name_ = ACE_TEXT(""); this->env_vars_.clear(); + this->jacorb_server_ = false; - if (attrs != 0 && attrs->getLength () == 9) + // if attrs exists and if the previously required 9 fields + const size_t previous_size = 9; + if (attrs != 0 && attrs->getLength () >= previous_size) { - this->server_id_ = attrs->getValue ((size_t)0); - this->server_name_ = attrs->getValue ((size_t)1); - this->activator_name_ = attrs->getValue ((size_t)2); - this->command_line_ = attrs->getValue ((size_t)3); - this->working_dir_ = attrs->getValue ((size_t)4); - this->activation_ = attrs->getValue ((size_t)5); + size_t index = 0; + this->server_id_ = attrs->getValue (index++); + this->server_name_ = attrs->getValue (index++); + this->activator_name_ = attrs->getValue (index++); + this->command_line_ = attrs->getValue (index++); + this->working_dir_ = attrs->getValue (index++); + this->activation_ = attrs->getValue (index++); this->env_vars_.clear (); - int limit = ACE_OS::atoi (attrs->getValue ((size_t)6)); + int limit = ACE_OS::atoi (attrs->getValue (index++)); this->start_limit_ = limit; - this->partial_ior_ = attrs->getValue ((size_t)7); - this->server_object_ior_ = attrs->getValue ((size_t)8); + this->partial_ior_ = attrs->getValue (index++); + this->server_object_ior_ = attrs->getValue (index++); + + if (attrs->getLength () >= index) + { + this->server_started_ = + (ACE_OS::atoi (attrs->getValue (index++)) != 0); + } + if (attrs->getLength () >= index) + { + this->jacorb_server_ = + (ACE_OS::atoi (attrs->getValue (index++)) != 0); + } + for ( ; index < attrs->getLength(); ++index) + { + this->extra_params_.push_back(std::make_pair( + attrs->getLocalName(index), attrs->getValue(index))); + } } } else if (ACE_OS::strcasecmp (qName, ACTIVATOR_INFO_TAG) == 0) { - if (attrs != 0 && attrs->getLength () == 3) + if (attrs != 0 && attrs->getLength () >= 3) { - ACE_CString aname = ACE_TEXT_ALWAYS_CHAR(attrs->getValue ((size_t)0)); - ACE_TString token_str = attrs->getValue ((size_t)1); + size_t index = 0; + const ACE_CString aname = + ACE_TEXT_ALWAYS_CHAR(attrs->getValue (index++)); + const ACE_TString token_str = attrs->getValue (index++); long token = ACE_OS::atoi (token_str.c_str ()); - ACE_CString ior = ACE_TEXT_ALWAYS_CHAR(attrs->getValue ((size_t)2)); - this->callback_.next_activator (aname, token, ior); + const ACE_CString ior = + ACE_TEXT_ALWAYS_CHAR(attrs->getValue (index++)); + NameValues extra_params; + for ( ; index < attrs->getLength(); ++index) + { + extra_params.push_back(std::make_pair( + attrs->getLocalName(index), attrs->getValue(index))); + } + this->repo_.load_activator (aname, token, ior, extra_params); } } else if (ACE_OS::strcasecmp (qName, ENVIRONMENT_TAG) == 0) @@ -73,11 +123,25 @@ Locator_XMLHandler::endElement (const ACEXML_Char*, if (ACE_OS::strcasecmp (qName, SERVER_INFO_TAG) == 0 && this->server_name_.length () > 0) { - this->callback_.next_server ( - this->server_id_, this->server_name_, - this->activator_name_, this->command_line_, - this->env_vars_, this->working_dir_, this->activation_, - this->start_limit_, this->partial_ior_, this->server_object_ior_); + const int limit = this->start_limit_ < 1 ? 1 : this->start_limit_; + ImplementationRepository::ActivationMode amode = + ImR_Utils::parseActivationMode (this->activation_); + + ImplementationRepository::EnvironmentList env_vars; + convertEnvList (this->env_vars_, env_vars); + this->repo_.load_server(this->server_id_, + this->server_name_, + this->jacorb_server_, + this->activator_name_, + this->command_line_, + env_vars, + this->working_dir_, + amode, + limit, + this->partial_ior_, + this->server_object_ior_, + this->server_started_, + this->extra_params_); } // activator info is handled in the startElement } diff --git a/TAO/orbsvcs/ImplRepo_Service/Locator_XMLHandler.h b/TAO/orbsvcs/ImplRepo_Service/Locator_XMLHandler.h index 643ea3408f3..4bffbdfb3cb 100644 --- a/TAO/orbsvcs/ImplRepo_Service/Locator_XMLHandler.h +++ b/TAO/orbsvcs/ImplRepo_Service/Locator_XMLHandler.h @@ -14,19 +14,23 @@ #include "ACEXML/common/DefaultHandler.h" -#include "ace/Vector_T.h" +#include "tao/ORB.h" + +#include <vector> #if !defined (ACE_LACKS_PRAGMA_ONCE) # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ +class XML_Backing_Store; /** - * Callback SAX XML Handler for parsing XML. + * Callback SAX XML Handler for parsing Locator XML. */ class Locator_XMLHandler : public ACEXML_DefaultHandler { public: - + typedef std::pair<ACE_CString, ACE_CString> NameValue; + typedef std::vector<NameValue> NameValues; // XML ELEMENT names static const ACE_TCHAR* ROOT_TAG; static const ACE_TCHAR* SERVER_INFO_TAG; @@ -40,41 +44,32 @@ public: bool operator!=(const EnvVar&) const; // To allow Vector explicit instantiation }; - typedef ACE_Vector<EnvVar> EnvList; - - struct Callback { - virtual ~Callback() {} - - virtual void next_server (const ACE_CString& server_id, - const ACE_CString& server_name, const ACE_CString& aname, - const ACE_CString& startup_cmd, const EnvList& env_vars, - const ACE_CString& working_dir, const ACE_CString& actmode, - int start_limit, const ACE_CString& partial_ior, - const ACE_CString& ior) = 0; + typedef std::vector<EnvVar> EnvList; - virtual void next_activator (const ACE_CString& activator_name, - long token, - const ACE_CString& ior) = 0; - }; - - Locator_XMLHandler (Callback& cb); + /// constructor + /// @param repo the repo to update based on XML + /// @param orb the orb (used to create server object) + Locator_XMLHandler (XML_Backing_Store& repo, CORBA::ORB_ptr orb); + /// provide implementation for handling a new XML element virtual void startElement (const ACEXML_Char* namespaceURI, const ACEXML_Char* localName, const ACEXML_Char* qName, ACEXML_Attributes* atts); + /// provide implementation for handling terminating an XML element virtual void endElement (const ACEXML_Char* namespaceURI, const ACEXML_Char* localName, const ACEXML_Char* qName); private: + /// the repository + XML_Backing_Store& repo_; - // callback on completion of an element - Callback& callback_; - + /// the server related parameters ACE_CString server_id_; ACE_TString server_name_; + bool jacorb_server_; ACE_TString activator_name_; ACE_TString command_line_; ACE_TString activation_; @@ -82,7 +77,14 @@ public: ACE_TString server_object_ior_; ACE_TString partial_ior_; int start_limit_; + bool server_started_; + NameValues extra_params_; + unsigned int repo_id_; + unsigned int repo_type_; EnvList env_vars_; + + /// the orb + CORBA::ORB_var orb_; }; #endif /* Locator_XMLHandler_H */ diff --git a/TAO/orbsvcs/ImplRepo_Service/README b/TAO/orbsvcs/ImplRepo_Service/README index 9579012f2d7..c5465941cc1 100644 --- a/TAO/orbsvcs/ImplRepo_Service/README +++ b/TAO/orbsvcs/ImplRepo_Service/README @@ -1,5 +1,7 @@ /** -*- HTML-Helper -*- $Id$ +$Id$ + @mainpage Implementation Repository @section intro Introduction @@ -30,7 +32,7 @@ as the specification for TAO's ImR. @ref ntservice - Running the ImR as a NT Service -@ref imrandnaming - Using the Naming Service with the Implmentation Repository +@ref imrandnaming - Using the Naming Service with the Implementation Repository @ref movefromoldImR - Moving from IMR as in TAO 1.2.2 to the present version. @@ -63,7 +65,7 @@ As with any program, there is always a wishlist of things to do. @subsection ort Use Object Reference Template (ORT) Features - Use ORT so that the ImR-ified IORs doesnt have any information + Use ORT so that the ImR-ified IORs doesn't have any information about the ImR_Activators. Right now, even though, the ImplRepo_Service is the one that is exposed to the client, the IOR will have a reference to the ImR_Activator. By using ORT features, we want the IOR to refer @@ -138,7 +140,7 @@ Nothing yet. @subsection XML Database Support As of now, the support is only to be able to have the information - about a registered server written to an XML file. Have to support + about a registered server written to an XML file. Have to support retrieving information from the XML file to be able to do any actions on the registered servers. @@ -161,7 +163,7 @@ communicate with an Implementation Repository, if one is available. @subsection description The New ImR - The new ImR is based on the ImR in TAO 1.2.2 with added + The new ImR is based on the ImR in TAO 1.2.2 with added features to help improve throughput and load balancing. The work to be performed by the Implementation Repository is distributed between two entities (ImplRepo_Service and ImR_Activator) to help achieve the goal of @@ -169,7 +171,7 @@ better throughput and load balance. @subsection locator ImplRepo_Service - The ImplRepo_Service acts as the main server which is visible to + The ImplRepo_Service acts as the main server which is visible to the application intending to use the ImR. It receives requests sent via tao_ImR and distributes the work to the registered ImR_Activators. It is stateless and does not maintain any information except about the @@ -186,39 +188,118 @@ Commandline Arguments that can be passed to ImplRepo_Service -o generate the ior. -x support persistence to the ImplRepo_Service. We use XML to support persistence. Names of the activators registered with the locator, - their IORs, and the servers registered with each of the activators are - saved to the xml file. Use this option to pass the name of the file - where the data has to be saved. - - And, ofcourse, the ORB Options. + their IORs, and the servers registered with each of the activators are + saved to the xml file. Use this option to pass the name of the file + where the data has to be saved. +-p similar to "-x" but using an ACE_Configuration_Heap file to persist + the data. +-r similar to "-p" but using an ACE_Configuration_Win32Registry to persist + the data. (only available on Win32 platforms) +--directory similar to "-x" option, but the repository will be written out + to multiple files in the indicated directory: "imr_listings.xml" which + indicates all servers and activators in the repository indicating the + filename containing that server's or activator's persistence data. + This option is used along with the "--primary" or "--backup" option + to create a Fault Tolerant ImplRepo_Service. +--primary pass along with "--directory <dir>" to startup the primary + ImR_Locator. See ft_imr_locator subsection. +--backup pass along with "--directory <dir>" to startup the backup + ImR_Locator. See ft_imr_locator subsection. + + And, of course, the ORB Options. + +@subsection ft_imr_locator FaultTolerant_ImR_Locator + +The ImR_Locator implements a fault tolerant service with the following options: + + The --primary option tells the ImR_Locator that it will startup as the primary + in a redundant service pair. + + The --backup option tells the ImR_Locator that it will startup as the backup + in a redundant service pair. + + The --directory <ft_imr_shared_dir> option tells the ImR_Locator the shared + file system directory to use as the backing store for the redundant service + pair. + + The -o <ft_imr_ior_filename> option tells the ImR_Locator to output the + redundant service pair ImRService ior file, which it can only do after + successfully starting the primary and backup ImRService instances. The ior + file contains the combined profiles of the primary and backup ImRLocators. The + client must use the ior file to use the fault tolerent ImplRepo_Service. + +The primary and backup ImRLocator instances should have the same ORBEndPoint +protocol list so that any client can send a request to either primary or backup +regardless of protocol (IIOP,UIOP,etc...). + +The ImR_Locator primary and backup options cannot be passed on the command +line along with -ORBObjRefStyle URL, since that style will cause the backup +profile to not be available in the ior. + +At startup the primary must be started first, then the backup. When +a single ImR_Locator goes down, it can be restarted at anytime +(using the same ORBEndPoints). If they are both shutdown then Fault Tolerant +ImplRepo_Service will be down until both the primary and backup are restarted +in that order.. The previous ior file will only remain valid if the ORBEndPoint +list remains the same for both instances. + +As long as both the primary and backup ImR_Locators are not shutdown at the +same time the Fault Tolerant ImplRepo_Service will always be available. + +@subsection ft_imr_locator_startup FaultTolerant_ImR_Locator Startup +<ol> + <li> + <em>Start the primary.</em><br> + It will write the replication ior to a file in the shared persistence + directory.<br> + <code> + tao_imr_locator + --primary + -ORBEndpoint <primary_hostname:port> + --directory <ft_imr_shared_dir> + </code> + </li> + <li> + </em>Start the backup.</em><br> + Reads the primary replication ior from the shared persistence directory.<br> + Writes the multi-profile ior to ft_imr_ior_filename<br>. + <code> + tao_imr_locator + --backup + -ORBEndpoint <backup_hostname:port> + --directory <ft_imr_shared_dir> + -o <ft_imr_ior_filename> + </code> + </li> +</ol> @subsection activator ImR_Activator - ImR_Activators, as you might have guessed, do the real work of + ImR_Activators, as you might have guessed, do the real work of activating servers or shutting them down and maintaining the information about servers related to them. Only one instance of an ImR_Activator can be run on one host. The ImR_Activator is not exposed at all to the application. Only the ImplRepo_Service needs to and it is the only one that can contact the ImR_Activator. - An instance of ImR_Activator first registers itself with the + An instance of ImR_Activator first registers itself with the ImplRepo_Service so that it can begin to receive requests. When registering with the ImplRepo_Service, it passes the hostname where it is being run and its IOR to the ImplRepo_Service. And, the ImplRepo_Service reaches it using the same information. -The Commandline paramters that are valid for ImR_Activator are +The Commandline parameters that are valid for ImR_Activator are --c: Run the Service command. +-c: Run the Service command. -d:number Debug Information --l lock the database. --o Generate the IOR to a file (just in case some one wants - to read the IOR) --r Enable Win32 regsitry implementation. --s Run as a service. --t Set a timeout value. --h Prints the help. +-l lock the database. +-o Generate the IOR to a file (just in case some one wants to read the + IOR) +-r Enable Win32 regsitry implementation. +-s Run as a service. +-t Set a timeout value. +-h Prints the help. When Persistence of an ImR_Activator is required, we will save the information about the server's that this ImR_Activator is related @@ -227,44 +308,44 @@ information about each server include its startup options, location, working directory which are needed to execute the requests that can passed by tao_imr with regards to the server. - There are two ways in which you can store data in the + There are two ways in which you can store data in the file. One way is to use ACE_Configuration_Heap to save all the information to the file. To do this, we have to pass the '-p' option. --p Pass the ImplRepo service a filename to use for the +-p Pass the ImplRepo service a filename to use for the backing store. Uses ACE_Configuration_Heap. - The second way is to save in XML-ized format. + The second way is to save in XML-ized format. --x Pass the filename where the repository information should +-x Pass the filename where the repository information should be saved. Use XML format. @subsection work So how does the whole thing work? - The first thing to do is to have an ImplRepo_Service running. Once + The first thing to do is to have an ImplRepo_Service running. Once the ImplRepo_Service is running, we can instantiate one or more ImR_Activators as needed per the application. As mentioned already, the ImR_Activators, upon instantiation, register with the ImplRepo_Service to be able to receive requests. - When a new server has to be added or any change has to the + When a new server has to be added or any change has to the done to an existing server, a request is to be sent to the ImplRepo_Service via the tao_imr utility. Startup commands, the working directory, the host where the server should be started up and such other information -are passed to the ImplRepo_Service via the TAO_ImR commandline arguments. +are passed to the ImplRepo_Service via the TAO_ImR command line arguments. - If the host where the server should be started up is passed + If the host where the server should be started up is passed while adding a new server, the ImplRepo_Service chooses the ImR_Activator that is running on that host to be responsible for the server's activities. Otherwise, an ImR_Activator is chosen based on the Round robin algorithm. We plan to use better algorithms based on the existing load for the same purpose in future. Whatever way the ImR_Activator is chosen for a server, once an ImR_Activator is chosen, -that ImR_Activator remains reponsible for the server throughout the +that ImR_Activator remains responsible for the server throughout the server's lifetime. - After an ImR_Activator is chosen, the ImplRepo_Service passes the + After an ImR_Activator is chosen, the ImplRepo_Service passes the request to the chosen ImR_Activator. The ImR_Activator acts on the request and updates its database to reflect the new state of the server. @@ -459,13 +540,13 @@ registered to it each time it starts up. The way to accomplish this is to add<br to the ImR_Activator's startup command line. The host name can be obtained portably in C++ code with the lines<br> - ACE_INET_addr ad;<br> - char *hostname = ad.get_host_name ();<br> + ACE_INET_addr ad;<br> + char *hostname = ad.get_host_name ();<br> or in a Perl script by adding<br> - use Sys::Hostname;<br> - $hostname = hostname();<br> + use Sys::Hostname;<br> + $hostname = hostname();<br> There are even specific port numbers, assigned to the OMG by the IANA, which can be used for this purpose. They are 683 (for IIOP) and 684 @@ -574,7 +655,7 @@ balance. <b>.</b> The added step that you would have to now do is run the ImR_Activator. You can just run one instance of it to get the same -behaviour as you were getting before. +behavior as you were getting before. If you run the ImplRepo_Service in multicast mode, the ImR_Activator will be able to get access to it via @@ -588,3 +669,4 @@ now be passed to the ImR_Activator since that is the one that is dealing with the database. */ + diff --git a/TAO/orbsvcs/ImplRepo_Service/Server_Info.cpp b/TAO/orbsvcs/ImplRepo_Service/Server_Info.cpp index d87476130f8..23ad5469001 100644 --- a/TAO/orbsvcs/ImplRepo_Service/Server_Info.cpp +++ b/TAO/orbsvcs/ImplRepo_Service/Server_Info.cpp @@ -5,6 +5,7 @@ Server_Info::Server_Info ( const ACE_CString& serverId, const ACE_CString& server_name, + bool jacorbs, const ACE_CString& aname, const ACE_CString& cmdline, const ImplementationRepository::EnvironmentList& env, @@ -16,6 +17,7 @@ Server_Info::Server_Info ImplementationRepository::ServerObject_ptr svrobj) : server_id (serverId) , name (server_name) + , jacorb_server( jacorbs) , activator (aname) , cmdline( cmdline) , env_vars (env) @@ -32,12 +34,22 @@ Server_Info::Server_Info } ImplementationRepository::ServerInformation* -Server_Info::createImRServerInfo (void) +Server_Info::createImRServerInfo (void) const { ImplementationRepository::ServerInformation* info; - ACE_NEW_THROW_EX (info, ImplementationRepository::ServerInformation, CORBA::NO_MEMORY ()); + ACE_NEW_THROW_EX (info, + ImplementationRepository::ServerInformation, + CORBA::NO_MEMORY ()); + + info->startup.command_line = cmdline.c_str (); + if (jacorb_server) + { + ACE_CString jacorb_name (ACE_TEXT ("JACORB:") + name); + info->server = jacorb_name.c_str(); + } + else + info->server = name.c_str(); - info->server = name.c_str (); info->startup.command_line = cmdline.c_str (); info->startup.environment = env_vars; info->startup.working_directory = dir.c_str (); @@ -63,5 +75,6 @@ Server_Info::reset (void) partial_ior = ""; last_ping = ACE_Time_Value::zero; server = ImplementationRepository::ServerObject::_nil (); - // start_count = 0; Note : We can't do this, because it would be reset during startup. + // start_count = 0; Note : We can't do this, because it would + // be reset during startup. } diff --git a/TAO/orbsvcs/ImplRepo_Service/Server_Info.h b/TAO/orbsvcs/ImplRepo_Service/Server_Info.h index 12403532beb..a1deb9f6acb 100644 --- a/TAO/orbsvcs/ImplRepo_Service/Server_Info.h +++ b/TAO/orbsvcs/ImplRepo_Service/Server_Info.h @@ -30,6 +30,7 @@ struct Server_Info { Server_Info (const ACE_CString& serverId, const ACE_CString& name, + bool jacorbs, const ACE_CString& aname, const ACE_CString& cmdline, const ImplementationRepository::EnvironmentList& env, @@ -42,13 +43,14 @@ struct Server_Info ); /// Convert to the corba type - ImplementationRepository::ServerInformation* createImRServerInfo(void); + ImplementationRepository::ServerInformation* createImRServerInfo(void) const; void reset(); /// The name of the server. ACE_CString server_id; ACE_CString name; + bool jacorb_server; /// The name of the activator in which this server runs ACE_CString activator; diff --git a/TAO/orbsvcs/ImplRepo_Service/Shared_Backing_Store.cpp b/TAO/orbsvcs/ImplRepo_Service/Shared_Backing_Store.cpp new file mode 100644 index 00000000000..b4cbb0dafff --- /dev/null +++ b/TAO/orbsvcs/ImplRepo_Service/Shared_Backing_Store.cpp @@ -0,0 +1,1366 @@ +// $Id$ + +#include "Shared_Backing_Store.h" +#include "Server_Info.h" +#include "Activator_Info.h" +#include "utils.h" +#include "Locator_XMLHandler.h" +#include "ImR_LocatorC.h" +#include "ace/File_Lock.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_strings.h" +#include "ace/OS_NS_ctype.h" +#include "ace/OS_NS_unistd.h" +#include "ACEXML/parser/parser/Parser.h" +#include "ACEXML/common/FileCharStream.h" +#include "ACEXML/common/XML_Util.h" +#include "tao/IORManipulation/IORManip_Loader.h" + +namespace { + class Lockable_File + { + public: + Lockable_File() + : file_(0), + flags_(0), + locked_(false), + unlink_in_destructor_(false) + { + } + + Lockable_File(const ACE_TString& file, + const int flags, + bool unlink_in_destructor = false) + : file_(0), + flags_(0), + locked_(false), + unlink_in_destructor_(false) + { + init_fl(file, flags, unlink_in_destructor); + } + + ~Lockable_File() + { + release(); + } + + void release() + { + if (this->file_ == 0) + return; + + close_file(); + this->file_lock_.reset(); + this->locked_ = false; + } + + FILE* get_file() + { + lock(); + + return this->file_; + } + + FILE* get_file(const ACE_TString& file, + const int flags, + bool unlink_in_destructor = false) + { + init_fl(file, flags, unlink_in_destructor); + return get_file(); + } + + private: + void init_fl(const ACE_TString& file, + const int flags, + bool unlink_in_destructor = false) + { + release(); + + flags_ = flags | O_CREAT; + unlink_in_destructor_ = unlink_in_destructor; + + const ACE_TCHAR* const flags_str = + ((flags_ & O_RDWR) != 0) ? ACE_TEXT("r+") : + (((flags_ & O_WRONLY) != 0) ? ACE_TEXT("w") : ACE_TEXT("r")); +#ifdef ACE_WIN32 + this->filename_ = file; + this->file_ = ACE_OS::fopen(file.c_str(), flags_str); +#else + this->file_lock_.reset( + new ACE_File_Lock(ACE_TEXT_CHAR_TO_TCHAR(file.c_str ()), + flags_, + 0666, + unlink_in_destructor)); + + // Truncating output so this will not allow reading then writing + + ACE_OS::ftruncate(this->file_lock_->get_handle(), 0); + this->file_ = ACE_OS::fdopen(this->file_lock_->get_handle(), flags_str); +#endif + } + + void close_file() + { + if (this->file_ == 0) + return; + + ACE_OS::fflush(this->file_); + ACE_OS::fclose(this->file_); + this->file_ = 0; +#ifdef ACE_WIN32 + if (this->unlink_in_destructor_) + { + ACE_OS::unlink(this->filename_.c_str()); + this->unlink_in_destructor_ = false; + } +#endif + } + + void lock() + { +#ifndef ACE_WIN32 + if (this->locked_) + return; + + if ((this->flags_ & O_RDWR) != 0) + file_lock_->acquire(); + if ((this->flags_ & O_WRONLY) != 0) + file_lock_->acquire_write(); + else + file_lock_->acquire_read(); + + this->locked_ = true; +#endif + } + + auto_ptr<ACE_File_Lock> file_lock_; + FILE* file_; + int flags_; + bool locked_; + bool unlink_in_destructor_; + ACE_TString filename_; + }; +} + +Shared_Backing_Store::Shared_Backing_Store(const Options& opts, + CORBA::ORB_ptr orb) +: XML_Backing_Store(opts, orb, true), + listing_file_(opts.persist_file_name() + ACE_TEXT("imr_listing.xml")), + seq_num_(0), + replica_seq_num_(0), + imr_type_(opts.imr_type()), + sync_needed_(NO_SYNC), + repo_id_(1), + repo_values_(2) +{ + IMR_REPLICA[Options::PRIMARY_IMR] = ACE_TEXT ("ImR_ReplicaPrimary"); + IMR_REPLICA[Options::BACKUP_IMR] = ACE_TEXT ("ImR_ReplicaBackup"); + IMR_REPLICA[Options::STANDALONE_IMR] = ACE_TEXT ("ImR_NoReplica"); + + this->repo_values_[REPO_TYPE] = + std::make_pair(ACE_CString(ACE_TEXT ("repo_type")), + ACE_CString()); + this->repo_values_[REPO_ID] = + std::make_pair(ACE_CString(ACE_TEXT ("repo_id")), + ACE_CString()); +} + +Shared_Backing_Store::~Shared_Backing_Store() +{ +} + + +static void replicate( + Shared_Backing_Store::Replica_ptr replica, + const ImplementationRepository::ServerUpdate& update) +{ + // replicate the ServerUpdate to our replicated locator + replica->notify_updated_server(update); +} + +static void replicate( + Shared_Backing_Store::Replica_ptr replica, + const ImplementationRepository::ActivatorUpdate& update) +{ + // replicate the ActivatorUpdate to our replicated locator + replica->notify_updated_activator(update); +} + +static void set_key(ImplementationRepository::ServerUpdate& update, + const Locator_Repository::SIMap::KEY& key) +{ + update.name = key.c_str(); +} + +static void set_key(ImplementationRepository::ActivatorUpdate& update, + const Locator_Repository::AIMap::KEY& key) +{ + update.name = key.c_str(); +} + +template< typename Update, typename Map> +static void replicate( + Shared_Backing_Store::Replica_ptr replica, + const typename Map::ENTRY& entry, + const ImplementationRepository::UpdateType type, + const ImplementationRepository::SequenceNum seq_num) +{ + if (CORBA::is_nil (replica)) + { + return; + } + + try + { + Update update; + set_key(update, entry.ext_id_); + update.type = type; + update.seq_num = seq_num; + update.repo_id = entry.int_id_.repo_id; + update.repo_type = entry.int_id_.repo_type; + replicate(replica, update); + } + catch (const CORBA::COMM_FAILURE&) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT("(%P|%t) Replicated ImR: COMM_FAILURE Exception\n"))); + } + catch (const CORBA::TRANSIENT&) + { + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT("(%P|%t) Replicated ImR: TRANSIENT Exception\n"))); + } + catch (const CORBA::OBJECT_NOT_EXIST&) + { + ACE_DEBUG (( + LM_DEBUG, + ACE_TEXT("(%P|%t) Replicated ImR: OBJECT_NOT_EXIST ") + ACE_TEXT("Exception, dropping replica\n"))); + replica = TAO::Objref_Traits + <ImplementationRepository::UpdatePushNotification>::nil (); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT("Replicated ImR: notify update")); + replica = 0; + } +} + +template<typename Map> +static typename Map::ENTRY& unique_id( + const typename Map::KEY& key, + Map& unique_ids, + const Shared_Backing_Store::UniqueId& id) +{ + typename Map::ENTRY* entry = 0; + unique_ids.bind(key, id, entry); + + return *entry; +} + +static Shared_Backing_Store::UniqueId create_uid( + const Options::ImrType repo_type, + const unsigned int repo_id) +{ + Shared_Backing_Store::UniqueId id; + id.repo_id = repo_id; + id.repo_type = repo_type; + ACE_TCHAR id_str[50]; + ACE_OS::itoa((unsigned int)repo_type, id_str, 10); + + id.repo_type_str = id_str; + + size_t current = ACE_OS::strlen(id_str); + id_str[current++] = ACE_TEXT('_'); + ACE_OS::itoa(repo_id, &(id_str[current]), 10); + + id.repo_id_str = &(id_str[current]); + + current = ACE_OS::strlen(id_str); + id_str[current++] = ACE_TEXT('.'); + id_str[current++] = ACE_TEXT('x'); + id_str[current++] = ACE_TEXT('m'); + id_str[current++] = ACE_TEXT('l'); + id_str[current++] = ACE_TEXT('\0'); + id.unique_filename = id_str; + + return id; +} + +template<typename Map> +static const typename Map::ENTRY& unique_id( + const typename Map::KEY& key, + Map& unique_ids, + const Options::ImrType type, + unsigned int& next_repo_id) +{ + typename Map::ENTRY* entry; + if (unique_ids.find(key, entry) == 0) + return *entry; + const unsigned int repo_id = next_repo_id++; + Shared_Backing_Store::UniqueId id = create_uid(type, repo_id); + return unique_id(key, unique_ids, id); +} + +static ACE_CString identify_key(const ACE_CString& name) +{ + ACE_CString id("name="); + id += name; + return id; +} + +/* TODO: bdj - will need this when server container changed to name and id +static ACE_CString identify_key(const Shared_Backing_Store::ServerKey& name) +{ + ACE_CString id("name="); + id += info.name; + return id; +} +*/ +template<typename Map> +static const typename Map::ENTRY& unique_id( + const typename Map::KEY& key, + Map& unique_ids, + const Options::ImrType this_repo_type, + unsigned int& this_repo_id, + Options::ImrType& entry_repo_type, + unsigned int& entry_repo_id) +{ + typename Map::ENTRY* temp_entry; + const bool found = (unique_ids.find(key, temp_entry) == 0); + + Shared_Backing_Store::UniqueId temp_id = + create_uid(entry_repo_type, entry_repo_id); + typename Map::ENTRY& entry = unique_id(key, unique_ids, temp_id); + + if (entry_repo_id == 0) + { + // if no repo id provided, treat it like it came from this repo + entry_repo_id = this_repo_id++; + entry_repo_type = this_repo_type; + } + else if (found) + { + Shared_Backing_Store::UniqueId& id = entry.int_id_; + if (entry_repo_id != id.repo_id && + entry_repo_type != id.repo_type) + { + // if already existed, replace the contents + ACE_ERROR(( + LM_ERROR, + ACE_TEXT("(%P|%t) ERROR: replacing %C with existing repo_id=%d ") + ACE_TEXT("and imr_type=%d, with repo_id=%d and imr_type=%d\n"), + identify_key(key).c_str(), id.repo_id, id.repo_type, + entry_repo_id, entry_repo_type)); + id = temp_id; + } + } + + if (entry_repo_type == this_repo_type && entry_repo_id >= this_repo_id) + { + // persisting existing entries for this repo, so move the repo_id past + // the entries id + this_repo_id = entry_repo_id + 1; + } + + return entry; +} + +template< typename Update, typename Map> +static int remove( + const typename Map::KEY& key, + const Map& unique_ids, + const ACE_TString& path, + Lockable_File& listing_lf, + Shared_Backing_Store::Replica_ptr peer_replica, + ImplementationRepository::SequenceNum& seq_num) +{ + typename Map::ENTRY* entry; + const int err = unique_ids.find(key, entry); + if (err != 0) + { + ACE_ERROR(( + LM_ERROR, + ACE_TEXT("(%P|%t) Couldn't find unique repo id for %C\n"), + identify_key(key).c_str())); + return err; + } + + const ACE_TString fname = path + entry->int_id_.unique_filename; + + { + // take the lock, then remove the file + Lockable_File file(fname, O_WRONLY, true); + } + listing_lf.release(); + + replicate<Update, Map> + (peer_replica, *entry, ImplementationRepository::repo_remove, ++seq_num); + + return 0; +} + +int +Shared_Backing_Store::persistent_remove (const ACE_CString& name, + bool activator) +{ + Lockable_File listing_lf; + int err = persist_listings(listing_lf); + if (err != 0) + { + return err; + } + + if (activator) + { + err = remove<ImplementationRepository::ActivatorUpdate> + (name, this->activator_uids_, this->filename_, listing_lf, + this->peer_replica_, this->seq_num_); + } + else + { + err = remove<ImplementationRepository::ServerUpdate> + (name, this->server_uids_, this->filename_, listing_lf, + this->peer_replica_, this->seq_num_); + } + return err; +} + +int +Shared_Backing_Store::persistent_update(const Server_Info_Ptr& info, bool add) +{ + Lockable_File listing_lf; + if (add) + { + const int err = persist_listings(listing_lf); + if (err != 0) + { + return err; + } + } + + ACE_CString name = ACEXML_escape_string (info->name); + + const ServerUIMap::ENTRY& entry = + unique_id(info->name, this->server_uids_, this->imr_type_, this->repo_id_); + const ACE_TString fname = this->filename_ + entry.int_id_.unique_filename; + if (this->opts_.debug() > 9) + { + ACE_DEBUG((LM_INFO, ACE_TEXT ("Persisting to %s(%C)\n"), + fname.c_str(), info->name.c_str())); + } + Lockable_File server_file(fname, O_WRONLY); + const ACE_TString bfname = fname.c_str() + ACE_TString(".bak"); + FILE* fp = server_file.get_file(); + if (fp == 0) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("Couldn't write to file %s\n"), + fname.c_str())); + return -1; + } + // successfully added file (if adding), so release the listing file lock + listing_lf.release(); + ACE_OS::fprintf (fp,"<?xml version=\"1.0\"?>\n"); + + this->repo_values_[REPO_TYPE].second = entry.int_id_.repo_type_str; + this->repo_values_[REPO_ID].second = entry.int_id_.repo_id_str; + + persist(fp, *info, "", this->repo_values_); + + // Copy the current file to a backup. + FILE* bfp = ACE_OS::fopen(bfname.c_str(),ACE_TEXT("w")); + ACE_OS::fprintf (bfp,"<?xml version=\"1.0\"?>\n"); + persist(bfp, *info, "", this->repo_values_); + ACE_OS::fflush(bfp); + ACE_OS::fclose(bfp); + server_file.release(); + + const ImplementationRepository::UpdateType type = add ? + ImplementationRepository::repo_add : + ImplementationRepository::repo_update; + replicate<ImplementationRepository::ServerUpdate, ServerUIMap> + (peer_replica_, entry, type, ++seq_num_); + return 0; +} + + +int +Shared_Backing_Store::persistent_update(const Activator_Info_Ptr& info, + bool add) +{ + Lockable_File listing_lf; + if (add) + { + const int err = persist_listings(listing_lf); + if (err != 0) + { + return err; + } + } + + ACE_CString name = lcase (info->name); + + const ActivatorUIMap::ENTRY& entry = + unique_id(name, this->activator_uids_, this->imr_type_, this->repo_id_); + const ACE_TString fname = this->filename_ + entry.int_id_.unique_filename; + if (this->opts_.debug() > 9) + { + ACE_DEBUG((LM_INFO, ACE_TEXT ("Persisting to %s(%C)\n"), + fname.c_str(), info->name.c_str())); + } + Lockable_File activator_file(fname, O_WRONLY); + const ACE_TString bfname = fname.c_str() + ACE_TString(".bak"); + FILE* fp = activator_file.get_file(); + if (fp == 0) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("Couldn't write to file %s\n"), + fname.c_str())); + return -1; + } + // successfully added file (if adding), so release the listing file lock + listing_lf.release(); + ACE_OS::fprintf (fp,"<?xml version=\"1.0\"?>\n"); + + this->repo_values_[REPO_TYPE].second = entry.int_id_.repo_type_str; + this->repo_values_[REPO_ID].second = entry.int_id_.repo_id_str; + + persist(fp, *info, "", this->repo_values_); + + // Copy the current file to a backup. + FILE* bfp = ACE_OS::fopen(bfname.c_str(),ACE_TEXT("w+")); + ACE_OS::fprintf (bfp,"<?xml version=\"1.0\"?>\n"); + persist(bfp, *info, "", this->repo_values_); + ACE_OS::fflush(bfp); + ACE_OS::fclose(bfp); + activator_file.release(); + + const ImplementationRepository::UpdateType type = add ? + ImplementationRepository::repo_add : + ImplementationRepository::repo_update; + replicate<ImplementationRepository::ActivatorUpdate, ActivatorUIMap> + (peer_replica_, entry, type, ++seq_num_); + return 0; +} + +const ACE_TCHAR* +Shared_Backing_Store::repo_mode() const +{ + return this->listing_file_.c_str(); +} + +int +Shared_Backing_Store::connect_replicas (Replica_ptr this_replica) +{ + const ACE_TString& replica_ior = replica_ior_filename(true); + if (this->opts_.debug() > 1) + { + ACE_DEBUG((LM_INFO, + ACE_TEXT("Resolving ImR replica %s\n"), replica_ior.c_str())); + } + + CORBA::Object_var obj = + this->orb_->string_to_object (replica_ior.c_str()); + + if (!CORBA::is_nil (obj.in ())) + { + bool non_exist = true; + try + { + this->peer_replica_ = ImplementationRepository:: + UpdatePushNotification::_narrow (obj.in()); + non_exist = (this->peer_replica_->_non_existent() == 1); + } + catch (const CORBA::Exception& ) + { + // let error be handled below + } + + if (non_exist) + { + this->peer_replica_ = + ImplementationRepository::UpdatePushNotification::_nil(); + } + } + + if (CORBA::is_nil (this->peer_replica_.in())) + { + if (this->imr_type_ == Options::BACKUP_IMR) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("Error: No primary ImR replica file found <%s>\n"), + replica_ior.c_str()), -1); + } + + // no connection currently, just wait for backup + return 0; + } + + if (opts_.debug() > 1) + { + ACE_DEBUG((LM_INFO, + ACE_TEXT("Registering with previously running ImR replica\n"))); + } + + try + { + this->peer_replica_->register_replica(this_replica, + this->imr_ior_.inout(), + this->replica_seq_num_); + } + catch (const ImplementationRepository::InvalidPeer& ip) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("Error: obj key <%s> is an invalid ImR replica because %s\n"), + replica_ior.c_str(), ip.reason.in()), -1); + } + + if (opts_.debug() > 9) + { + ACE_DEBUG((LM_INFO, + ACE_TEXT("Initializing repository with ft ior=<%C> ") + ACE_TEXT("and replica seq number %d\n"), + this->imr_ior_.in(), replica_seq_num_)); + } + + return 0; +} + +int +Shared_Backing_Store::init_repo(PortableServer::POA_ptr imr_poa) +{ + this->non_ft_imr_ior_ = this->imr_ior_; + PortableServer::ObjectId_var id = + PortableServer::string_to_ObjectId ("ImR_Replica"); + imr_poa->activate_object_with_id (id.in (), this); + + if (this->imr_type_ != Options::STANDALONE_IMR) + { + CORBA::Object_var obj = imr_poa->id_to_reference (id.in ()); + + Replica_var this_replica = + ImplementationRepository::UpdatePushNotification::_narrow (obj.in()); + const int err = connect_replicas(this_replica.in()); + if (err != 0) + { + return err; + } + } + + // only start the repo clean if no replica is running + if (this->opts_.repository_erase() && + CORBA::is_nil (this->peer_replica_.in ())) + { + Lockable_File listing_lf; + const XMLHandler_Ptr listings = get_listings(listing_lf, false); + if (listings.null()) + { + if (this->opts_.debug() > 9) + { + ACE_DEBUG((LM_INFO, + ACE_TEXT ("Persisted Repository already empty\n"))); + } + } + else + { + const ACE_Vector<ACE_TString>& filenames = listings->filenames(); + CORBA::ULong sz = filenames.size (); + for (CORBA::ULong i = 0; i < sz; ++i) + { + if (this->opts_.debug() > 9) + { + ACE_DEBUG((LM_INFO, ACE_TEXT ("Removing %s\n"), + filenames[i].c_str())); + } + ACE_OS::unlink ( filenames[i].c_str () ); + } + + if (this->opts_.debug() > 9) + { + ACE_DEBUG((LM_INFO, ACE_TEXT ("Removing %s\n"), + this->listing_file_.c_str())); + } + ACE_OS::unlink ( this->listing_file_.c_str () ); + } + } + + // ignore persistent_load return since files don't have to exist + persistent_load(false); + + if (this->opts_.debug() > 9) + { + ACE_DEBUG((LM_INFO, + ACE_TEXT ("ImR Repository initialized\n"))); + } + + return 0; +} + +int +Shared_Backing_Store::persistent_load (bool only_changes) +{ + Lockable_File listing_lf; + const XMLHandler_Ptr listings = get_listings(listing_lf, only_changes); + if (listings.null()) + { + // failed to retrieve listings + return -1; + } + + if (only_changes) + { + listings->remove_unmatched(*this); + } + + const ACE_Vector<ACE_TString>& filenames = listings->filenames(); + CORBA::ULong sz = filenames.size (); + if (this->opts_.debug() > 9) + { + ACE_DEBUG((LM_INFO, ACE_TEXT ("persistent_load %d files\n"), sz)); + } + for (CORBA::ULong i = 0; i < sz; ++i) + { + const ACE_TString& fname = filenames[i]; + Lockable_File file(fname, O_RDONLY); + + if(load(fname, file.get_file()) != 0) + { + load(fname + ".bak"); + } + } + + return 0; +} + +Shared_Backing_Store::XMLHandler_Ptr +Shared_Backing_Store::get_listings(Lockable_File& listing_lf, + bool only_changes) const +{ + XMLHandler_Ptr listings_handler; + if (only_changes) + { + listings_handler.reset(new LocatorListings_XMLHandler( + this->filename_, servers(), activators())); + } + else + { + listings_handler.reset(new LocatorListings_XMLHandler(this->filename_)); + } + + if (load(this->listing_file_, + *listings_handler, + this->opts_.debug(), + listing_lf.get_file(this->listing_file_, O_RDONLY)) != 0) + { + + if (load(this->listing_file_ + ".bak", + *listings_handler, + this->opts_.debug()) != 0) + { + listings_handler.reset(); + } + } + + return listings_handler; +} + +int +Shared_Backing_Store::sync_load () +{ + int err = 0; + if (this->opts_.debug() > 5) + { + ACE_DEBUG(( + LM_INFO, + ACE_TEXT("(%P|%t) sync_load %d, %d\n"), + this->sync_needed_, this->sync_files_.size())); + } + if (this->sync_needed_ == FULL_SYNC) + { + err = persistent_load(false); + } + else if (this->sync_needed_ == INC_SYNC) + { + std::set<ACE_TString>::const_iterator fname = this->sync_files_.begin(); + for ( ; fname != this->sync_files_.end(); ++fname) + { + if (this->opts_.debug() > 6) + { + ACE_DEBUG((LM_INFO, + ACE_TEXT("(%P|%t) sync_load %s\n"), + fname->c_str())); + } + Lockable_File file(*fname, O_RDONLY); + int ind_err = load(*fname, file.get_file()); + if (ind_err != 0) + { + err = ind_err; + } + } + this->sync_files_.clear(); + } + + this->sync_needed_ = NO_SYNC; + return err; +} + +static void write_listing_item(FILE* list, const ACE_TString& fname, + const ACE_CString& name, const ACE_TCHAR* tag) +{ + ACE_OS::fprintf (list, "\t<%s", tag); + ACE_OS::fprintf (list, " fname=\"%s\"", fname.c_str ()); + ACE_OS::fprintf (list, " name=\"%s\" />\n", name.c_str ()); +} + +void +Shared_Backing_Store::write_listing(FILE* list) +{ + ACE_OS::fprintf (list,"<?xml version=\"1.0\"?>\n"); + ACE_OS::fprintf (list,"<ImRListing>\n"); + + // Save servers + Locator_Repository::SIMap::ENTRY* sientry = 0; + Locator_Repository::SIMap::CONST_ITERATOR siit (this->servers ()); + for (; siit.next (sientry); siit.advance() ) + { + const Server_Info_Ptr& info = sientry->int_id_; + + const Shared_Backing_Store::ServerUIMap::ENTRY& entry = + unique_id(sientry->ext_id_, this->server_uids_, + this->imr_type_, this->repo_id_); + ACE_CString listing_name = ACEXML_escape_string (info->name); + write_listing_item(list, entry.int_id_.unique_filename, listing_name, + Locator_XMLHandler::SERVER_INFO_TAG); + } + + // Save Activators + Locator_Repository::AIMap::ENTRY* aientry = 0; + Locator_Repository::AIMap::CONST_ITERATOR aiit (this->activators ()); + for (; aiit.next (aientry); aiit.advance ()) + { + const ACE_CString& aname = aientry->ext_id_; + const ActivatorUIMap::ENTRY& entry = + unique_id(aname, this->activator_uids_, + this->imr_type_, this->repo_id_); + write_listing_item(list, entry.int_id_.unique_filename, aname, + Locator_XMLHandler::ACTIVATOR_INFO_TAG); + } + + ACE_OS::fprintf (list,"</ImRListing>\n"); +} + +int +Shared_Backing_Store::persist_listings (Lockable_File& listing_lf) +{ + FILE* list = listing_lf.get_file(this->listing_file_, O_WRONLY); + if (list == 0) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("Couldn't write to file %s\n"), + this->listing_file_.c_str())); + return -1; + } + + write_listing(list); + + const ACE_TString bfname = this->listing_file_.c_str() + ACE_TString(".bak"); + + // Write backup file + FILE* baklist = ACE_OS::fopen(bfname.c_str(),ACE_TEXT("w")); + if (baklist == 0) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("Couldn't write to file %s\n"), + bfname.c_str())); + return -1; + } + + write_listing(baklist); + ACE_OS::fflush(baklist); + ACE_OS::fclose(baklist); + + return 0; +} + +int +Shared_Backing_Store::report_ior(PortableServer::POA_ptr imr_poa) +{ + if (this->imr_type_ == Options::STANDALONE_IMR) + { + return Locator_Repository::report_ior(imr_poa); + } + + CORBA::Object_var obj = this->orb_->resolve_initial_references ("IORTable"); + IORTable::Table_var ior_table = IORTable::Table::_narrow (obj.in ()); + ACE_ASSERT (! CORBA::is_nil (ior_table.in ())); + + const char* const replica_name(IMR_REPLICA[this->imr_type_]); + ACE_TString replica_filename = replica_ior_filename(false); + FILE* fp = ACE_OS::fopen (replica_filename.c_str (), "w"); + if (fp == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("ImR: Could not open file: %s\n"), + replica_filename.c_str ()), -1); + } + obj = imr_poa->servant_to_reference (this); + const CORBA::String_var replica_ior = this->orb_->object_to_string (obj.in ()); + ior_table->bind(replica_name, replica_ior.in()); + ACE_OS::fprintf (fp, "%s", replica_ior.in ()); + ACE_OS::fclose (fp); + + int err = 0; + // only report the imr ior if the fault tolerant ImR is complete + if (!CORBA::is_nil (this->peer_replica_.in())) + { + err = Locator_Repository::report_ior(imr_poa); + } + + return err; +} + +char* +Shared_Backing_Store::locator_service_ior(const char* peer_ior) const +{ + const CORBA::Object_ptr this_obj = + this->orb_->string_to_object(this->non_ft_imr_ior_.in()); + const CORBA::Object_ptr peer_obj = + this->orb_->string_to_object(peer_ior); + const CORBA::Object_ptr& obj1 = + (this->imr_type_ == Options::PRIMARY_IMR) ? this_obj : peer_obj; + const CORBA::Object_ptr& obj2 = + (this->imr_type_ != Options::PRIMARY_IMR) ? this_obj : peer_obj; + + CORBA::Object_var IORM = + this->orb_->resolve_initial_references (TAO_OBJID_IORMANIPULATION, 0); + + TAO_IOP::TAO_IOR_Manipulation_var iorm = + TAO_IOP::TAO_IOR_Manipulation::_narrow (IORM.in()); + + CORBA::Object_var locator_service = iorm->add_profiles(obj1, obj2); + + char* const combined_ior = + this->orb_->object_to_string(locator_service.in()); + return combined_ior; + +} + +template<typename Map> +static const typename Map::ENTRY& unique_id( + const typename Map::KEY& key, + const XML_Backing_Store::NameValues& repo_values, + const XML_Backing_Store::NameValues& extra_params, + Map& unique_ids, + const Options::ImrType this_repo_type, + unsigned int& this_repo_id, + const unsigned int debug) +{ + const unsigned int size = extra_params.size(); + if ((size != 2) && (debug > 4)) + { + ACE_ERROR(( + LM_ERROR, + ACE_TEXT("(%P|%t) Persisted server id=%C name=%C doesn't have all ") + ACE_TEXT("unique id params. (%d of 2)\n"), + size)); + }; + + unsigned int repo_id = 0; + // default to this repo + Options::ImrType repo_type = this_repo_type; + for (unsigned int i = 0; i < size; ++i) + { + ACE_DEBUG((LM_INFO, + ACE_TEXT ("name values %C=%C (%C)\n"), + extra_params[i].first.c_str(), + extra_params[i].second.c_str(), + repo_values[i].first.c_str())); + } + if ((size > Shared_Backing_Store::REPO_TYPE) && + (extra_params[Shared_Backing_Store::REPO_TYPE].first == + repo_values[Shared_Backing_Store::REPO_TYPE].first)) + repo_type = (Options::ImrType)ACE_OS::atoi( + extra_params[Shared_Backing_Store::REPO_TYPE].second.c_str()); + + if ((size > Shared_Backing_Store::REPO_ID) && + (extra_params[Shared_Backing_Store::REPO_ID].first == + repo_values[Shared_Backing_Store::REPO_ID].first)) + repo_id = + ACE_OS::atoi(extra_params[Shared_Backing_Store::REPO_ID].second.c_str()); + else + { + ACE_ERROR((LM_ERROR, + ACE_TEXT("(%P|%t) Persisted %C did not supply a repo_id\n"), + identify_key(key).c_str())); + } + + return + unique_id(key, unique_ids, this_repo_type, + this_repo_id, repo_type, repo_id); +} + +void +Shared_Backing_Store::load_server ( + const ACE_CString& server_id, + const ACE_CString& server_name, + bool jacorb_server, + const ACE_CString& activator_name, + const ACE_CString& startup_cmd, + const ImplementationRepository::EnvironmentList& env_vars, + const ACE_CString& working_dir, + const ImplementationRepository::ActivationMode actmode, + int start_limit, + const ACE_CString& partial_ior, + const ACE_CString& ior, + bool server_started, + const NameValues& extra_params) +{ + // ensure there is an entry for this server + unique_id(server_name, this->repo_values_, extra_params, + this->server_uids_, this->imr_type_, this->repo_id_, + this->opts_.debug()); + Server_Info_Ptr si; + const bool new_server = (this->servers ().find (server_name, si) != 0); + + if (new_server) + { + // create new or replace the existing entry + XML_Backing_Store::load_server( + server_id, server_name, jacorb_server, activator_name, startup_cmd, + env_vars, working_dir, actmode, start_limit, partial_ior, ior, + server_started, extra_params); + return; + } + + // is the server object new + const bool new_ior = si->ior != ior; + if (new_ior) + si->ior = ior; + + si->server_id = server_id; + si->jacorb_server = jacorb_server; + si->activator = activator_name; + si->cmdline = startup_cmd; + si->env_vars = env_vars; + si->dir = working_dir; + si->activation_mode = actmode; + si->start_limit = start_limit; + si->partial_ior = partial_ior; + + if (!server_started) + si->server = ImplementationRepository::ServerObject::_nil(); + else + // will create a new server below if no previous server + // or the ior has changed + server_started = CORBA::is_nil(si->server) || new_ior; + + create_server(server_started, si); +} + +void +Shared_Backing_Store::load_activator (const ACE_CString& activator_name, + long token, + const ACE_CString& ior, + const NameValues& extra_params) +{ + // use this to make sure an unique id entry is created + unique_id(activator_name, this->repo_values_, extra_params, + this->activator_uids_, this->imr_type_, this->repo_id_, + this->opts_.debug()); + XML_Backing_Store::load_activator(activator_name, token, ior, extra_params); +} + +void +Shared_Backing_Store::notify_updated_server( + const ImplementationRepository::ServerUpdate& server) +{ + if (this->opts_.debug() > 5) + { + ACE_DEBUG(( + LM_INFO, + ACE_TEXT("(%P|%t) notify_updated_server=%C\n"), + server.name.in())); + } + if ((this->sync_needed_ == FULL_SYNC) || + (++this->replica_seq_num_ != server.seq_num)) + { + this->replica_seq_num_ = server.seq_num; + this->sync_needed_ = FULL_SYNC; + this->sync_files_.clear(); + return; + } + + const ACE_CString name = server.name.in(); + if (server.type == ImplementationRepository::repo_remove) + { + // sync_needed_ doesn't change, since we handle the change + // imme;diately + this->servers().unbind (name); + return; + } + + this->sync_needed_ = INC_SYNC; + Options::ImrType repo_type = (Options::ImrType)server.repo_type; + unsigned int repo_id = server.repo_id; + const ServerUIMap::ENTRY& entry = + unique_id(name, this->server_uids_, this->imr_type_, this->repo_id_, + repo_type, repo_id); + const ACE_TString fname = this->filename_ + entry.int_id_.unique_filename; + this->sync_files_.insert(fname); +} + +void +Shared_Backing_Store::notify_updated_activator( + const ImplementationRepository::ActivatorUpdate& activator) +{ + if (this->opts_.debug() > 5) + { + ACE_DEBUG(( + LM_INFO, + ACE_TEXT("(%P|%t) notify_updated_activator=%C\n"), + activator.name.in())); + } + if ((this->sync_needed_ == FULL_SYNC) || + (++this->replica_seq_num_ != activator.seq_num)) + { + this->replica_seq_num_ = activator.seq_num; + this->sync_needed_ = FULL_SYNC; + this->sync_files_.clear(); + return; + } + + const ACE_CString name = lcase(activator.name.in()); + if (activator.type == ImplementationRepository::repo_remove) + { + // sync_needed_ doesn't change, since we handle the change + // immediately + this->activators().unbind (name); + return; + } + + this->sync_needed_ = INC_SYNC; + Options::ImrType repo_type = (Options::ImrType)activator.repo_type; + unsigned int repo_id = activator.repo_id; + const ActivatorUIMap::ENTRY& entry = + unique_id(name, this->activator_uids_, this->imr_type_, this->repo_id_, + repo_type, repo_id); + const ACE_TString fname = this->filename_ + entry.int_id_.unique_filename; + this->sync_files_.insert(fname); +} + +void +Shared_Backing_Store::register_replica( + ImplementationRepository::UpdatePushNotification_ptr replica, + char*& ft_imr_ior, + ImplementationRepository::SequenceNum_out seq_num) +{ + ACE_ASSERT (! CORBA::is_nil (replica)); + this->peer_replica_ = + ImplementationRepository::UpdatePushNotification::_duplicate (replica); + + seq_num = this->seq_num_; + if (this->imr_type_ == Options::STANDALONE_IMR) + { + ACE_ERROR((LM_ERROR, + ACE_TEXT("Error: Non-replicated ImR receiving replica ") + ACE_TEXT("registration <%s>\n"), + ft_imr_ior)); + return; + } + + this->replica_seq_num_ = 0; + + // store off original char* to ensure memory cleanup + CORBA::String_var ior = ft_imr_ior; + + // if we already have the fault tolerant ImR ior + // then just copy it + if (registered()) + { + if (this->opts_.debug() > 2) + { + ACE_DEBUG(( + LM_INFO, + ACE_TEXT("(%P|%t) Already registered <%C>\n"), + this->imr_ior_.in())); + } + // make a copy + ior = this->imr_ior_.in(); + // handoff memory + ft_imr_ior = ior._retn(); + return; + } + + // otherwise we need to combine the primary and backup ior to make + // the fault tolerant ImR ior + char* combined_ior = 0; + CORBA::String_var reason; + try + { + combined_ior = locator_service_ior(ft_imr_ior); + } + catch (const TAO_IOP::Invalid_IOR& ) + { + reason = "invalid ior"; + } + catch (const TAO_IOP::EmptyProfileList& ) + { + reason = "no profiles"; + } + catch (const TAO_IOP::Duplicate& ) + { + reason = "duplicate profile"; + } + + if (combined_ior == 0) + { + // give back the original pointer and don't clean it up + ft_imr_ior = ior._retn(); + ACE_ERROR((LM_ERROR, + "ERROR: Failed to create Fault Tolerant ImR, reason=%s\n", + reason.in())); + throw ImplementationRepository::InvalidPeer(reason.in()); + } + + ft_imr_ior = combined_ior; + // pass as const char* to make sure string is copied + this->imr_ior_ = (const char*)ft_imr_ior; + + PortableServer::POA_var null_poa; + Locator_Repository::report_ior(null_poa); +} + +ACE_CString +Shared_Backing_Store::replica_ior_filename(bool peer_ior_file) const +{ + Options::ImrType desired_type = this->imr_type_; + if (peer_ior_file) + { + desired_type = (desired_type == Options::PRIMARY_IMR) ? + Options::BACKUP_IMR : + Options::PRIMARY_IMR; + } + ACE_CString ior = + this->filename_ + IMR_REPLICA[desired_type] + ACE_TEXT(".ior"); + if (peer_ior_file) + { + // the peer ior file needs the file prefix + ior = "file://" + ior; + } + + return ior; +} + +Shared_Backing_Store::LocatorListings_XMLHandler::LocatorListings_XMLHandler( + const ACE_TString& dir) +: dir_(dir), + only_changes_(false) +{ +} + +Shared_Backing_Store::LocatorListings_XMLHandler::LocatorListings_XMLHandler( + const ACE_TString& dir, + const Locator_Repository::SIMap& servers, + const Locator_Repository::AIMap& activators) +: dir_(dir), + only_changes_(true) +{ + Locator_Repository::SIMap::ENTRY* sientry = 0; + Locator_Repository::SIMap::CONST_ITERATOR siit (servers); + for (; siit.next (sientry); siit.advance() ) + { + unmatched_servers_.bind (sientry->ext_id_, sientry->int_id_); + } + + Locator_Repository::AIMap::ENTRY* aientry = 0; + Locator_Repository::AIMap::CONST_ITERATOR aiit (activators); + for (; aiit.next (aientry); aiit.advance() ) + { + unmatched_activators_.bind (aientry->ext_id_, aientry->int_id_); + } +} + +void +Shared_Backing_Store::LocatorListings_XMLHandler::startElement ( + const ACEXML_Char* , + const ACEXML_Char* , + const ACEXML_Char* qName, + ACEXML_Attributes* attrs) +{ + const bool server = + (ACE_OS::strcasecmp (qName, Locator_XMLHandler::SERVER_INFO_TAG) == 0); + if (!server && + (ACE_OS::strcasecmp (qName, Locator_XMLHandler::ACTIVATOR_INFO_TAG) != 0)) + { + return; + } + + if (attrs != 0 && attrs->getLength () == 2) + { + ACE_TString fname = attrs->getValue ((size_t)0); + bool store_fname = !only_changes_; + if (only_changes_) + { + ACE_CString name = ACE_TEXT_ALWAYS_CHAR(attrs->getValue ((size_t)1)); + // if the name is not present, then this is an add, so store it + store_fname = server ? + (unmatched_servers_.unbind (name) != 0) : + (unmatched_activators_.unbind (name) != 0); + } + + if (store_fname) + { + filenames_.push_back(dir_ + fname); + } + } + else + ACE_DEBUG(( + LM_INFO, + ACE_TEXT ("LocatorListings_XMLHandler::startElement ") + ACE_TEXT ("incorrect number of attrs (%d)\n"), + attrs->getLength ())); + +} + +void +Shared_Backing_Store::LocatorListings_XMLHandler::endElement ( + const ACEXML_Char* , + const ACEXML_Char* , + const ACEXML_Char* ) +{ +} + +void +Shared_Backing_Store::LocatorListings_XMLHandler::remove_unmatched( + Locator_Repository& repo) +{ + Locator_Repository::SIMap::ENTRY* sientry = 0; + Locator_Repository::SIMap::CONST_ITERATOR siit (this->unmatched_servers_); + for (; siit.next (sientry); siit.advance() ) + { + int ret = repo.servers().unbind (sientry->ext_id_); + if (ret != 0) + { + ACE_ERROR((LM_ERROR, + ACE_TEXT ("ERROR: could not remove server: %s\n"), + sientry->int_id_->name.c_str())); + } + } + + Locator_Repository::AIMap::ENTRY* aientry = 0; + Locator_Repository::AIMap::CONST_ITERATOR aiit (this->unmatched_activators_); + for (; aiit.next (aientry); aiit.advance ()) + { + int ret = repo.activators().unbind (aientry->ext_id_); + if (ret != 0) + { + ACE_ERROR((LM_ERROR, + ACE_TEXT ("ERROR: could not remove activator: %s\n"), + aientry->int_id_->name.c_str())); + } + } +} + +const ACE_Vector<ACE_TString>& +Shared_Backing_Store::LocatorListings_XMLHandler::filenames() const +{ + return this->filenames_; +} diff --git a/TAO/orbsvcs/ImplRepo_Service/Shared_Backing_Store.h b/TAO/orbsvcs/ImplRepo_Service/Shared_Backing_Store.h new file mode 100644 index 00000000000..fc235ba2b88 --- /dev/null +++ b/TAO/orbsvcs/ImplRepo_Service/Shared_Backing_Store.h @@ -0,0 +1,302 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** +* @file Shared_Backing_Store.h +* +* $Id$ +* +* This class defines an implementation of the backing store as multiple XML files +* shared between multiple Locators. +* +* @author Darrell Brunsch <brunsch@cs.wustl.edu> +* @author Priyanka Gontla <gontla_p@ociweb.com> +*/ +//============================================================================= + +#ifndef SHARED_BACKING_STORE_H +#define SHARED_BACKING_STORE_H + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "XML_Backing_Store.h" + +#include "ImR_LocatorS.h" +#include "ace/Bound_Ptr.h" +#include "ace/Vector_T.h" +#include "ACEXML/common/DefaultHandler.h" + +#include <set> + +class ACE_Configuration; +class ACEXML_FileCharStream; +class LocatorListings_XMLHandler; + +namespace { + class Lockable_File; +} + +/** +* @class Shared_Backing_Store +* +* @brief XML backing store containing all ImR persistent information in +* multiple files shared between multiple Locators +* +*/ +class Shared_Backing_Store + : public XML_Backing_Store, + public virtual POA_ImplementationRepository::UpdatePushNotification +{ +public: + typedef ImplementationRepository::UpdatePushNotification_var Replica_var; + typedef ImplementationRepository::UpdatePushNotification_ptr Replica_ptr; + struct UniqueId + { + Options::ImrType repo_type; + unsigned int repo_id; + ACE_TString repo_type_str; + ACE_TString repo_id_str; + ACE_TString unique_filename; + }; + typedef ACE_Hash_Map_Manager_Ex<ServerKey, + UniqueId, + ACE_Hash<ServerKey>, + ACE_Equal_To<ServerKey>, + ACE_Null_Mutex> ServerUIMap; + + typedef ACE_Hash_Map_Manager_Ex<ActivatorKey, + UniqueId, + ACE_Hash<ActivatorKey>, + ACE_Equal_To<ActivatorKey>, + ACE_Null_Mutex> ActivatorUIMap; + + enum ExtraParams { REPO_TYPE = 0, REPO_ID = 1 }; + + Shared_Backing_Store(const Options& opts, + CORBA::ORB_ptr orb); + + virtual ~Shared_Backing_Store(); + + /// indicate the persistence mode for the repository + virtual const ACE_TCHAR* repo_mode() const; + + /// provide the implementation for being notified of a + /// server update + virtual void notify_updated_server( + const ImplementationRepository::ServerUpdate& server); + + /// provide the implementation for being notified of a + /// activator update + virtual void notify_updated_activator( + const ImplementationRepository::ActivatorUpdate& activator); + + /// provide the implementation for registering a peer replica + /// @param replica the peer replica + /// @param ft_imr_ior the fault tolerant ImR IOR (passed in + /// as the replica's ImR IOR, passed back as fault + /// tolerant ImR IOR) + /// @param seq_num current sequence number to return to replica + virtual void register_replica( + ImplementationRepository::UpdatePushNotification_ptr replica, + char*& ft_imr_ior, + ImplementationRepository::SequenceNum_out seq_num); + + /// enum to indicate whether the repo is in-sync, individual + /// server and/or activator files need to be sync-ed or if + /// a full sync of servers and activators is needed + enum SyncType { NO_SYNC, INC_SYNC, FULL_SYNC }; + + /// create the Server_Info server object + /// @param server_id the Server_Info server_id + /// @param server_name the Server_Info server_name + /// @param activator_name the Server_Info activator + /// @param cmdline the Server_Info cmdline + /// @param env_vars the Server_Info env_vars + /// @param workin_dir the Server_Info dir + /// @param actmode the Server_Info activation_mode + /// @param start_limit the Server_Info start_limit + /// @param partial_ior the Server_Info partial_ior + /// @param ior the Server_Info ior + /// @param server_started indicates if the server object + /// existed when data was persisted + /// @param extra_params extra name value pairs that + /// were reported for the server + virtual void load_server ( + const ACE_CString& server_id, + const ACE_CString& server_name, + bool jacorb_server, + const ACE_CString& activator_name, + const ACE_CString& cmdline, + const ImplementationRepository::EnvironmentList& env_vars, + const ACE_CString& working_dir, + ImplementationRepository::ActivationMode actmode, + int start_limit, + const ACE_CString& partial_ior, + const ACE_CString& ior, + bool server_started, + const NameValues& extra_params); + + /// create the Activator_Info activator object + /// @param activator_name the Activator_Info name + /// @param token the Activator_Info token + /// @param ior the Activator_Info ior + /// @param extra_params extra name value pairs that + /// were reported for the activator + virtual void load_activator (const ACE_CString& activator_name, + long token, + const ACE_CString& ior, + const NameValues& extra_params); +protected: + /// perform shared backing store specific initialization + /// (activates this Shared_Backing_Store as the "ImR_Replica", + /// trys to connect to the peer replica, unless it is a + /// STANDALONE_IMR, clears out the persisted store if needed, + /// and loads the repo from the persisted store) + virtual int init_repo(PortableServer::POA_ptr imr_poa); + + /// perform server persistent update + virtual int persistent_update(const Server_Info_Ptr& info, bool add); + + /// perform activator persistent update + virtual int persistent_update(const Activator_Info_Ptr& info, bool add); + + /// perform persistent remove + virtual int persistent_remove(const ACE_CString& name, bool activator); + + /// perform sync of repo with backing store + /// uses sync_needed_ and sync_files_ to determine what to update + virtual int sync_load (); + + /// calls Locator_Repository::report_ior with the Fault Tolerant ImR + /// Locator's IOR if available, otherwise reporting the ior is delayed + /// until the peer replica registers with this replica + virtual int report_ior(PortableServer::POA_ptr imr_poa); + + /// create the Fault Tolerant ImR Locator IOR, using the peer_ior and + /// this ImR Locator's IOR + char* locator_service_ior(const char* peer_ior) const; + +private: + /** + * Callback SAX XML Handler for parsing the imr_listings.xml file. + */ + class LocatorListings_XMLHandler : public ACEXML_DefaultHandler + { + public: + /// constructor + /// @param dir the directory path to add to the server or activator + /// filename + LocatorListings_XMLHandler(const ACE_TString& dir); + + /// constructor for tracking only changes to what servers and activators + /// are currently in the repo + /// @param dir the directory path to add to the server or activator + /// filename + /// @param servers a map of servers currently in the repo + /// @param servers a map of activators currently in the repo + LocatorListings_XMLHandler(const ACE_TString& dir, + const Locator_Repository::SIMap& servers, + const Locator_Repository::AIMap& activators); + + /// provide implementation for handling a new XML element + virtual void startElement (const ACEXML_Char* namespaceURI, + const ACEXML_Char* localName, + const ACEXML_Char* qName, + ACEXML_Attributes* attrs); + + /// provide implementation for handling terminating an XML element + virtual void endElement (const ACEXML_Char* namespaceURI, + const ACEXML_Char* localName, + const ACEXML_Char* qName); + + /// remove the servers and activators that were in the repo but not + /// in the listings file (this does nothing if existing servers and + /// activators were not provided in constructor) + void remove_unmatched(Locator_Repository& repo); + + /// the filenames identified in the listings file, if tracking changes + /// only then only the filenames of the new servers and activators + const ACE_Vector<ACE_TString>& filenames() const; + + private: + /// the directory to add to the listings file relative filenames + const ACE_TString& dir_; + /// the filenames identified in the listings file (or the new filenames) + ACE_Vector<ACE_TString> filenames_; + /// the existing servers in the repo that were not present in the + /// listings file + Locator_Repository::SIMap unmatched_servers_; + /// the existing activators in the repo that were not present in the + /// listings file + Locator_Repository::AIMap unmatched_activators_; + /// indicates if only changes should be tracked + const bool only_changes_; + }; + typedef ACE_Strong_Bound_Ptr + <LocatorListings_XMLHandler, ACE_Null_Mutex> XMLHandler_Ptr; + + /// determine the filename where the replica ior is reported + /// @param peer_ior_file if this is the filename for the peer + /// replica or this replica + ACE_CString replica_ior_filename(bool peer_ior_file) const; + + /// get the listings file contents + /// @param listing_lf a Lockable_File for the listings file + /// that will be locked when the function returns + /// @param only_changes if only changes to the repo should be + /// reported + /// @return a pointer to the LocatorListings_XMLHandler + XMLHandler_Ptr get_listings(Lockable_File& listing_lf, + bool only_changes) const; + + /// perform a persistent load from the backing store + /// @param only_changes if only changes to the repo should be + /// loaded + int persistent_load(bool only_changes); + + /// persistent the listings file + /// @param listing_lf a Lockable_File for the listings file + /// that will be locked when the function returns + int persist_listings(Lockable_File& listing_lf); + + /// write content to the listings file and optionally its backup + /// @param File pointer to write to. Can be primary or backup. + void write_listing(FILE *); + + /// connect this replica to its peer replica + /// @param this_replica a pointer to this Replica object + int connect_replicas(Replica_ptr this_replica); + + /// the path and filename for the listings file + const ACE_TString listing_file_; + /// the path and filename for the listings file + Replica_var peer_replica_; + /// the current sequence number for reporting changes made directly to + /// this repo + ImplementationRepository::SequenceNum seq_num_; + /// the current sequence number last reported by the peer replica + ImplementationRepository::SequenceNum replica_seq_num_; + /// the imr type of this Shared_Backing_Store + const Options::ImrType imr_type_; + /// the current type of sync needed by the repo + SyncType sync_needed_; + /// the server and activator files that need to be updated for + /// sync_needed_ == INC_SYNC + std::set<ACE_TString> sync_files_; + /// the ior for just this ImR Locator + CORBA::String_var non_ft_imr_ior_; + /// an array associating ImrType with the appropriate name + const char* IMR_REPLICA[3]; + /// map for server unique ids + ServerUIMap server_uids_; + /// map for activator unique ids + ActivatorUIMap activator_uids_; + /// next unique repo id + unsigned int repo_id_; + /// extra parameters for XML + XML_Backing_Store::NameValues repo_values_; +}; + +#endif /* SHARED_BACKING_STORE_H */ diff --git a/TAO/orbsvcs/ImplRepo_Service/XML_Backing_Store.cpp b/TAO/orbsvcs/ImplRepo_Service/XML_Backing_Store.cpp new file mode 100644 index 00000000000..1f7e6822fa8 --- /dev/null +++ b/TAO/orbsvcs/ImplRepo_Service/XML_Backing_Store.cpp @@ -0,0 +1,323 @@ +// $Id$ + +#include "XML_Backing_Store.h" +#include "Server_Info.h" +#include "Activator_Info.h" +#include "utils.h" +#include "Locator_XMLHandler.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_strings.h" +#include "ace/OS_NS_ctype.h" +#include "ace/OS_NS_unistd.h" +#include "ACEXML/parser/parser/Parser.h" +#include "ACEXML/common/FileCharStream.h" +#include "ACEXML/common/XML_Util.h" + +XML_Backing_Store::XML_Backing_Store(const Options& opts, + CORBA::ORB_ptr orb, + bool suppress_erase) +: Locator_Repository(opts, orb), + filename_(opts.persist_file_name()) +{ + if (opts.repository_erase() && !suppress_erase) + { + ACE_OS::unlink ( this->filename_.c_str () ); + } +} + +XML_Backing_Store::~XML_Backing_Store() +{ +} + +int +XML_Backing_Store::persistent_remove (const ACE_CString& , bool ) +{ + // one big XML file, need to persist everything + return persist(); +} + +int +XML_Backing_Store::persistent_update(const Server_Info_Ptr& , bool ) +{ + // one big XML file, need to persist everything + return persist(); +} + +int +XML_Backing_Store::persistent_update(const Activator_Info_Ptr& , bool ) +{ + // one big XML file, need to persist everything + return persist(); +} + +int +XML_Backing_Store::persist () +{ + FILE* fp = ACE_OS::fopen (this->filename_.c_str (), "w"); + if (fp == 0) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("Couldn't write to file %C\n"), + this->filename_.c_str())); + return -1; + } + ACE_OS::fprintf (fp,"<?xml version=\"1.0\"?>\n"); + ACE_OS::fprintf (fp,"<%s>\n", Locator_XMLHandler::ROOT_TAG); + + // Save servers + Locator_Repository::SIMap::ENTRY* sientry = 0; + Locator_Repository::SIMap::ITERATOR siit (this->servers ()); + for (; siit.next (sientry); siit.advance() ) + { + persist(fp, *sientry->int_id_, "\t"); + } + + // Save Activators + Locator_Repository::AIMap::ENTRY* aientry = 0; + Locator_Repository::AIMap::ITERATOR aiit (this->activators ()); + for (; aiit.next (aientry); aiit.advance ()) + { + ACE_CString aname = aientry->ext_id_; + persist(fp, *aientry->int_id_, "\t"); + } + + ACE_OS::fprintf (fp,"</%s>\n", Locator_XMLHandler::ROOT_TAG); + ACE_OS::fclose (fp); + + return 0; +} + +void +XML_Backing_Store::persist (FILE* fp, + const Server_Info& info, + const char* tag_prepend, + const NameValues& name_values) +{ + ACE_CString server_id = ACEXML_escape_string (info.server_id); + ACE_CString name = ACEXML_escape_string (info.name); + ACE_CString activator = ACEXML_escape_string (info.activator); + ACE_CString cmdline = ACEXML_escape_string (info.cmdline); + ACE_CString wdir = ACEXML_escape_string (info.dir); + ACE_CString partial_ior = ACEXML_escape_string (info.partial_ior); + ACE_CString ior = ACEXML_escape_string (info.ior); + + ACE_OS::fprintf (fp,"%s<%s", tag_prepend, + Locator_XMLHandler::SERVER_INFO_TAG); + ACE_OS::fprintf (fp," server_id=\"%s\"", server_id.c_str ()); + ACE_OS::fprintf (fp," name=\"%s\"", name.c_str ()); + ACE_OS::fprintf (fp," activator=\"%s\"", activator.c_str ()); + ACE_OS::fprintf (fp," command_line=\"%s\"", cmdline.c_str ()); + ACE_OS::fprintf (fp," working_dir=\"%s\"", wdir.c_str ()); + ACE_CString amodestr = + ImR_Utils::activationModeToString (info.activation_mode); + ACE_OS::fprintf (fp," activation_mode=\"%s\"", amodestr.c_str ()); + ACE_OS::fprintf (fp," start_limit=\"%d\"", info.start_limit); + ACE_OS::fprintf (fp," partial_ior=\"%s\"", partial_ior.c_str ()); + ACE_OS::fprintf (fp," ior=\"%s\"", ior.c_str ()); + ACE_OS::fprintf (fp," started=\"%d\"", !CORBA::is_nil(info.server.in())); + ACE_OS::fprintf (fp," jacorb_server=\"%d\"", info.jacorb_server); + + NameValues::const_iterator name_value; + for (name_value = name_values.begin(); name_value != name_values.end(); ++name_value) + { + ACE_OS::fprintf (fp," %s=\"%s\"", + name_value->first.c_str(), name_value->second.c_str()); + } + + const CORBA::ULong length = info.env_vars.length (); + if (length > 0) + { + ACE_OS::fprintf (fp,">\n"); + for (CORBA::ULong i = 0; i < info.env_vars.length (); ++i) + { + ACE_OS::fprintf (fp,"%s\t<%s", tag_prepend, + Locator_XMLHandler::ENVIRONMENT_TAG); + ACE_OS::fprintf (fp," name=\"%s\"", info.env_vars[i].name.in ()); + ACE_CString val = ACEXML_escape_string(info.env_vars[i].value.in()); + ACE_OS::fprintf (fp," value=\"%s\"", val.c_str()); + ACE_OS::fprintf (fp,"/>\n"); + } + + ACE_OS::fprintf (fp,"%s</%s>\n", tag_prepend, + Locator_XMLHandler::SERVER_INFO_TAG); + } + else + { + ACE_OS::fprintf (fp,"/>\n"); + } +} + +void +XML_Backing_Store::persist (FILE* fp, + const Activator_Info& info, + const char* tag_prepend, + const NameValues& name_values) +{ + ACE_OS::fprintf (fp,"%s<%s", tag_prepend, + Locator_XMLHandler::ACTIVATOR_INFO_TAG); + ACE_OS::fprintf( fp," name=\"%s\"", info.name.c_str ()); + ACE_OS::fprintf (fp," token=\"%d\"", info.token); + ACE_OS::fprintf (fp," ior=\"%s\"", info.ior.c_str ()); + + NameValues::const_iterator name_value; + for (name_value = name_values.begin(); name_value != name_values.end(); ++name_value) + { + ACE_OS::fprintf (fp," %s=\"%s\"", + name_value->first.c_str(), name_value->second.c_str()); + } + + ACE_OS::fprintf (fp,"/>\n"); +} + +int +XML_Backing_Store::init_repo(PortableServer::POA_ptr ) +{ + // ignore load return since files don't have to exist + load(this->filename_); + return 0; +} + +int +XML_Backing_Store::load (const ACE_TString& filename, FILE* open_file) +{ + Locator_XMLHandler xml_handler (*this, this->orb_.in()); + return load(filename, xml_handler, this->opts_.debug(), open_file); +} + +int +XML_Backing_Store::load (const ACE_TString& filename, + ACEXML_DefaultHandler& xml_handler, + unsigned int debug, + FILE* open_file) +{ + // xml input source will take ownership + ACEXML_FileCharStream* fstm; + ACE_NEW_RETURN (fstm, + ACEXML_FileCharStream, + -1); + + int err; + // use the open_file stream if it is provided + if (open_file != 0) + err = fstm->use_stream(open_file, + filename.c_str()); + else + err = fstm->open (filename.c_str()); + + if (debug > 9) + { + ACE_DEBUG ((LM_INFO, ACE_TEXT ("load %s%C\n"), filename.c_str(), + ((err == 0) ? ACE_TEXT ("") + : ACE_TEXT (" (file doesn't exist)")))); + } + + if (err != 0) + { + delete fstm; + return err; + } + + ACEXML_Parser parser; + + // InputSource takes ownership + ACEXML_InputSource input (fstm); + + parser.setContentHandler (&xml_handler); + parser.setDTDHandler (&xml_handler); + parser.setErrorHandler (&xml_handler); + parser.setEntityResolver (&xml_handler); + + try + { + parser.parse (&input); + } + catch (const ACEXML_Exception& ex) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Error during load of ImR persistence xml file (%s)."), + filename.c_str())); + ex.print (); + return -1; + } + catch ( const ACEXML_SAXParseException* sax_ex) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Error during load of ImR persistence xml file (%s)."), + filename.c_str())); + sax_ex->print (); + return -1; + } + + + + return 0; +} + +const ACE_TCHAR* +XML_Backing_Store::repo_mode() const +{ + return this->filename_.c_str(); +} + +void +XML_Backing_Store::load_server ( + const ACE_CString& server_id, + const ACE_CString& server_name, + bool jacorb_server, + const ACE_CString& activator_name, + const ACE_CString& startup_cmd, + const ImplementationRepository::EnvironmentList& env_vars, + const ACE_CString& working_dir, + ImplementationRepository::ActivationMode actmode, + int start_limit, + const ACE_CString& partial_ior, + const ACE_CString& ior, + bool server_started, + const NameValues& ) +{ + const int limit = start_limit < 1 ? 1 : start_limit; + + Server_Info *serv_inf; + ACE_NEW (serv_inf, + Server_Info (server_id, server_name, jacorb_server, + activator_name, startup_cmd, env_vars, + working_dir, actmode, limit, + partial_ior, ior)); + + Server_Info_Ptr si (serv_inf); + + this->servers().rebind(server_name, si); + + create_server(server_started, si); +} + +void +XML_Backing_Store::create_server(bool server_started, + const Server_Info_Ptr& si) +{ + if (!server_started || si->ior.is_empty()) + return; + + CORBA::Object_var obj = this->orb_->string_to_object(si->ior.c_str()); + if (!CORBA::is_nil(obj.in())) + { + si->server = + ImplementationRepository::ServerObject::_unchecked_narrow (obj.in()); + si->last_ping = ACE_Time_Value::zero; + } + else + si->server = ImplementationRepository::ServerObject::_nil(); +} + +void +XML_Backing_Store::load_activator (const ACE_CString& activator_name, + long token, + const ACE_CString& ior, + const NameValues& ) +{ + Activator_Info *ai; + ACE_NEW (ai, + Activator_Info (activator_name, token, ior)); + + Activator_Info_Ptr info (ai); + this->activators().rebind(activator_name, info); +} diff --git a/TAO/orbsvcs/ImplRepo_Service/XML_Backing_Store.h b/TAO/orbsvcs/ImplRepo_Service/XML_Backing_Store.h new file mode 100644 index 00000000000..b4fe9900d5a --- /dev/null +++ b/TAO/orbsvcs/ImplRepo_Service/XML_Backing_Store.h @@ -0,0 +1,161 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** +* @file XML_Backing_Store.h +* +* $Id$ +* +* This class defines an implementation of the backing store as a single XML file. +* +* @author Darrell Brunsch <brunsch@cs.wustl.edu> +* @author Priyanka Gontla <gontla_p@ociweb.com> +*/ +//============================================================================= + +#ifndef XML_BACKING_STORE_H +#define XML_BACKING_STORE_H + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "Locator_Repository.h" + +#include <vector> + +class ACE_Configuration; +class ACEXML_FileCharStream; +class ACEXML_DefaultHandler; + +/** +* @class XML_Backing_Store +* +* @brief XML backing store interface containing all ImR persistent information +* in a single file +* +*/ +class XML_Backing_Store : public Locator_Repository +{ +public: + typedef std::pair<ACE_CString, ACE_CString> NameValue; + typedef std::vector<NameValue> NameValues; + XML_Backing_Store(const Options& opts, + CORBA::ORB_ptr orb, + bool suppress_erase = false); + + virtual ~XML_Backing_Store(); + + /// indicate the XML filename as the persistence mode for the repository + virtual const ACE_TCHAR* repo_mode() const; + + /// create the Server_Info server object + /// @param server_id the Server_Info server_id + /// @param server_name the Server_Info server_name + /// @param activator_name the Server_Info activator + /// @param cmdline the Server_Info cmdline + /// @param env_vars the Server_Info env_vars + /// @param workin_dir the Server_Info dir + /// @param actmode the Server_Info activation_mode + /// @param start_limit the Server_Info start_limit + /// @param partial_ior the Server_Info partial_ior + /// @param ior the Server_Info ior + /// @param server_started indicates if the server object + /// existed when data was persisted + /// @param extra_params extra name value pairs that + /// were reported for the server + virtual void load_server ( + const ACE_CString& server_id, + const ACE_CString& server_name, + bool jacorb_server, + const ACE_CString& activator_name, + const ACE_CString& cmdline, + const ImplementationRepository::EnvironmentList& env_vars, + const ACE_CString& working_dir, + ImplementationRepository::ActivationMode actmode, + int start_limit, + const ACE_CString& partial_ior, + const ACE_CString& ior, + bool server_started, + const NameValues& extra_params); + + /// create the Activator_Info activator object + /// @param activator_name the Activator_Info name + /// @param token the Activator_Info token + /// @param ior the Activator_Info ior + /// @param extra_params extra name value pairs that + /// were reported for the activator + virtual void load_activator (const ACE_CString& activator_name, + long token, + const ACE_CString& ior, + const NameValues& extra_params); +protected: + /// perform XML backing store specific initialization + /// (loads servers and activators from the backing store) + virtual int init_repo(PortableServer::POA_ptr imr_poa); + + /// perform server persistent update + virtual int persistent_update(const Server_Info_Ptr& info, bool add); + + /// perform activator persistent update + virtual int persistent_update(const Activator_Info_Ptr& info, bool add); + + /// perform persistent remove + virtual int persistent_remove(const ACE_CString& name, bool activator); + + /// load the contents of a file into the repo using a Locator_XMLHandler + /// @param filename the filename to read the contents from + /// @param open_file the already open FILE stream for the + /// filename + int load(const ACE_TString& filename, FILE* open_file = 0); + + /// load the contents of a file into the repo using the provided + /// ACEXML_DefaultHandler + /// @param filename the filename to read the contents from + /// @param xml_handler the ACEXML_DefaultHandler to use to parse + /// the file + /// @param open_file the already open FILE stream for the + /// filename + static int load(const ACE_TString& filename, + ACEXML_DefaultHandler& xml_handler, + unsigned int debug, + FILE* open_file = 0); + + /// persist the server + /// @param fp the FILE stream to persist the server contents to + /// @param info the Server_Info to persist + /// @param tag_prepend a character string to prepend at the start + /// of every xml line to maintain proper indentation + /// @param name_values extra name value pairs to write as attributes + void persist(FILE* fp, + const Server_Info& info, + const char* tag_prepend, + const NameValues& name_values = NameValues()); + + /// persist the activator + /// @param fp the FILE stream to persist the activator contents to + /// @param info the Server_Info to persist + /// @param tag_prepend a character string to prepend at the start + /// of every xml line to maintain proper indentation + /// @param name_values extra name value pairs to write as attributes + void persist(FILE* fp, + const Activator_Info& info, + const char* tag_prepend, + const NameValues& name_values = NameValues()); + + /// create the Server_Info server object + /// @param server_started indication from persistence indicating if the + /// server object was present + /// @param si the server info in question + void create_server(bool server_started, const Server_Info_Ptr& si); + +protected: + /// the filename indicated in the Options for the backing store + const ACE_TString filename_; + +private: + /// persist all servers and activators + int persist(); +}; + +#endif /* XML_BACKING_STORE_H */ diff --git a/TAO/orbsvcs/ImplRepo_Service/tao_imr_i.cpp b/TAO/orbsvcs/ImplRepo_Service/tao_imr_i.cpp index 674a60b437a..2837ef12135 100644 --- a/TAO/orbsvcs/ImplRepo_Service/tao_imr_i.cpp +++ b/TAO/orbsvcs/ImplRepo_Service/tao_imr_i.cpp @@ -817,9 +817,18 @@ TAO_IMR_Op_IOR::run (void) ACE_CString ior (imr_str.in ()); // Add the key - ior += this->server_name_; + const char jacorb[] = ACE_TEXT_ALWAYS_CHAR ("JACORB:"); + const char *posjacorb = ACE_OS::strstr (server_name_.c_str (), jacorb); + if (posjacorb) + { + ior += posjacorb + sizeof(jacorb) - 1; + } + else + { + ior += this->server_name_; + } - ACE_DEBUG ((LM_DEBUG, "%s\n", ior.c_str ())); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%s\n"), ior.c_str ())); if (this->filename_.length () > 0) { @@ -828,7 +837,7 @@ TAO_IMR_Op_IOR::run (void) if (file == 0) { ACE_ERROR_RETURN ((LM_ERROR, - "Error: Unable to open %s for writing: %p\n", + ACE_TEXT ("Error: Unable to open %s for writing: %p\n"), this->filename_.c_str ()), -1); } diff --git a/TAO/orbsvcs/Naming_Service/FT_Naming_Main.cpp b/TAO/orbsvcs/Naming_Service/FT_Naming_Main.cpp new file mode 100644 index 00000000000..4086db3d9a4 --- /dev/null +++ b/TAO/orbsvcs/Naming_Service/FT_Naming_Main.cpp @@ -0,0 +1,64 @@ +// $Id$ + +#include "FT_Naming_Service.h" +#include "ace/OS_main.h" + +#include "orbsvcs/Shutdown_Utilities.h" +#include "tao/debug.h" + +#include "tao/ImR_Client/ImR_Client.h" + +class Naming_Svc_Shutdown : public Shutdown_Functor +{ +public: + Naming_Svc_Shutdown (TAO_Naming_Service& ns); + + void operator() (int which_signal); +private: + TAO_Naming_Service& ns_; +}; + +Naming_Svc_Shutdown::Naming_Svc_Shutdown (TAO_Naming_Service& ns) + : ns_(ns) +{ +} + +void +Naming_Svc_Shutdown::operator() (int which_signal) +{ + if (TAO_debug_level > 0) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("FT Name Service: shutting down on signal %d\n"), + which_signal)); + (void) this->ns_.shutdown (); +} + +// Driver function for the TAO FT Naming Service. + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + TAO_FT_Naming_Service naming_service; + + // Stuff to insure that we're gracefully shut down... + Naming_Svc_Shutdown killer (naming_service); + Service_Shutdown kill_contractor(killer); + + if (naming_service.init (argc, argv) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("Failed to start the Naming Service.\n")), + 1); + try + { + naming_service.run (); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("NamingService")); + return 1; + } + + naming_service.fini (); + + return 0; +} diff --git a/TAO/orbsvcs/Naming_Service/FT_Naming_Service.cpp b/TAO/orbsvcs/Naming_Service/FT_Naming_Service.cpp new file mode 100644 index 00000000000..913c39088f8 --- /dev/null +++ b/TAO/orbsvcs/Naming_Service/FT_Naming_Service.cpp @@ -0,0 +1,31 @@ +// $Id$ + +#include "FT_Naming_Service.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Server.h" +#include "orbsvcs/Naming/Persistent_Naming_Context_Factory.h" + +// Default Constructor. +TAO_FT_Naming_Service::TAO_FT_Naming_Service (void) +{ +} + +// Constructor taking command-line arguments. +TAO_FT_Naming_Service::TAO_FT_Naming_Service (int argc, ACE_TCHAR* argv[]) + : TAO_Naming_Service (argc, argv) +{ +} + + + +/// Create a server object for the naming service +TAO_Naming_Server* +TAO_FT_Naming_Service::create_naming_server () +{ + return new (ACE_nothrow) TAO_FT_Naming_Server (); +} + + +// Destructor. +TAO_FT_Naming_Service::~TAO_FT_Naming_Service (void) +{ +} diff --git a/TAO/orbsvcs/Naming_Service/FT_Naming_Service.h b/TAO/orbsvcs/Naming_Service/FT_Naming_Service.h new file mode 100644 index 00000000000..3d77b0e0de5 --- /dev/null +++ b/TAO/orbsvcs/Naming_Service/FT_Naming_Service.h @@ -0,0 +1,52 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file FT_Naming_Service.h + * + * $Id$ + * + * This class provides an override for the Naming_Service class factory + * method: create_naming_server () + * + * @author Kevin Stanley <stanleyk@ociweb.com> + */ +//========================================================================== + + +#ifndef TAO_FT_NAMING_SERVICE_H +#define TAO_FT_NAMING_SERVICE_H + +#include /**/ "Naming_Service.h" + +#include "tao/ORB.h" + +class TAO_Naming_Server; + +/** + * @class TAO_FT_Naming_Service + * + * @brief Defines a class that encapsulates the implementation of the + * Fault Tolerant Naming Service. + * + * This class overrides the create_naming_server factory method inherited + * from <TAO_Naming_Service>. + */ +class TAO_FT_Naming_Service : public TAO_Naming_Service +{ +public: + /// Default Constructor. + TAO_FT_Naming_Service (void); + + /// Constructor taking the command-line arguments. + TAO_FT_Naming_Service (int argc, ACE_TCHAR* argv[]); + + /// Factory method to create a server object for the naming service + virtual TAO_Naming_Server* create_naming_server (); + + /// Destructor. + virtual ~TAO_FT_Naming_Service (void); + +}; + +#endif /* TAO_FT_NAMING_SERVICE_H */ diff --git a/TAO/orbsvcs/Naming_Service/Naming_Service.cpp b/TAO/orbsvcs/Naming_Service/Naming_Service.cpp index bb1a7fe56d7..73682314357 100644 --- a/TAO/orbsvcs/Naming_Service/Naming_Service.cpp +++ b/TAO/orbsvcs/Naming_Service/Naming_Service.cpp @@ -2,6 +2,7 @@ #include "Naming_Service.h" +#include "orbsvcs/Naming/Naming_Server.h" #include "orbsvcs/Daemon_Utilities.h" #include "ace/Get_Opt.h" #include "ace/Argv_Type_Converter.h" @@ -9,14 +10,16 @@ // Default Constructor. TAO_Naming_Service::TAO_Naming_Service (void) - : time_ (0), + : my_naming_server_ (0), + time_ (0), num_threads_ (1) { } // Constructor taking command-line arguments. TAO_Naming_Service::TAO_Naming_Service (int argc, ACE_TCHAR* argv[]) - : time_ (0), + : my_naming_server_(0), + time_ (0), num_threads_ (1) { this->init (argc, argv); @@ -41,14 +44,26 @@ TAO_Naming_Service::init (int argc, ACE_TCHAR* argv[]) // arguments. this->parse_args (argc, argv); + // Factory method used to construct a naming server to be used in + // creation and initialization of the naming service components. + this->my_naming_server_ = this->create_naming_server (); + + // For some reason we are unable to create a naming server. + if (this->my_naming_server_ == 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("TAO_Naming_Service::init -- ") + ACE_TEXT ("Unable to create a Naming_Server. Exiting.\n")), + -1); + // This function call initializes the naming service and returns // '-1' in case of an exception. - int const result = this->my_naming_server_.init_with_orb (argc, + int const result = this->my_naming_server_->init_with_orb (argc, argv, this->orb_.in ()); if (result == -1) return result; + } catch (const CORBA::Exception& ex) { @@ -172,7 +187,7 @@ TAO_Naming_Service::shutdown (void) int TAO_Naming_Service::fini (void) { - this->my_naming_server_.fini(); + this->my_naming_server_->fini(); try { @@ -190,8 +205,18 @@ TAO_Naming_Service::fini (void) return 0; } +/// Factory method used to create a server object for the naming service +TAO_Naming_Server* +TAO_Naming_Service::create_naming_server () +{ + // Default behavior is to use the Naming_Server located in orbsvcs\orbsvcs\Naming + return new (ACE_nothrow) TAO_Naming_Server; +} + + // Destructor. TAO_Naming_Service::~TAO_Naming_Service (void) { - // Destructor + // Invoke destructor of naming server which was created using the factory method + delete this->my_naming_server_; } diff --git a/TAO/orbsvcs/Naming_Service/Naming_Service.h b/TAO/orbsvcs/Naming_Service/Naming_Service.h index 71a2eb6e211..abcf7df0516 100644 --- a/TAO/orbsvcs/Naming_Service/Naming_Service.h +++ b/TAO/orbsvcs/Naming_Service/Naming_Service.h @@ -17,7 +17,10 @@ #ifndef TAO_NAMING_SERVICE_H #define TAO_NAMING_SERVICE_H -#include "orbsvcs/Naming/Naming_Server.h" +#include /**/ "ace/pre.h" +#include "tao/ORB.h" + +class TAO_Naming_Server; /** * @class TAO_Naming_Service @@ -44,10 +47,13 @@ public: virtual int fini (void); /// Run the TAO_Naming_Service. - int run (void); + virtual int run (void); /// Shut down the TAO_Naming_Service; you must still call fini(). - void shutdown (void); + virtual void shutdown (void); + + /// Factory method to create a server object for the naming service + virtual TAO_Naming_Server* create_naming_server (); /// Destructor. virtual ~TAO_Naming_Service (void); @@ -62,7 +68,7 @@ protected: CORBA::ORB_var orb_; /// Naming Server instance. - TAO_Naming_Server my_naming_server_; + TAO_Naming_Server* my_naming_server_; /// After how long the server should stop listening to requests (in /// seconds). @@ -72,4 +78,6 @@ protected: int num_threads_; }; +#include /**/ "ace/post.h" + #endif /* TAO_NAMING_SERVICE_H */ diff --git a/TAO/orbsvcs/Naming_Service/Naming_Service.mpc b/TAO/orbsvcs/Naming_Service/Naming_Service.mpc index cba797ebd34..e8052b297d4 100644 --- a/TAO/orbsvcs/Naming_Service/Naming_Service.mpc +++ b/TAO/orbsvcs/Naming_Service/Naming_Service.mpc @@ -13,6 +13,18 @@ project : orbsvcsexe, install, naming_serv, imr_client, svc_utils { } } +project (FT_Naming_Service) : orbsvcsexe, install, ft_naming_serv, naming_serv, imr_client, svc_utils { + exename = tao_ft_naming + Header_Files { + FT_Naming_Service.h + } + Source_Files { + FT_Naming_Main.cpp + FT_Naming_Service.cpp + Naming_Service.cpp + } +} + project(NT_Naming_Service) : orbsvcsexe, install, naming_serv, svc_utils { requires += winnt exename = tao_nt_cosnaming diff --git a/TAO/orbsvcs/Naming_Service/README b/TAO/orbsvcs/Naming_Service/README index c6f84e5ddf6..7030d444f6a 100644 --- a/TAO/orbsvcs/Naming_Service/README +++ b/TAO/orbsvcs/Naming_Service/README @@ -13,17 +13,18 @@ The following describes how to run the TAO Naming Service. 1. Syntax % Naming_Service [-ORBNameServicePort nsport] + [-b base_address] + [-d ] + [-f persistence_file_name] + [-m (1=enable multicast responses,0=disable(default)] + [-n number_of_threads] [-o ior_output_file] [-p pid_file_name] + [-r directory] [-s context_size] [-t time] - [-f persistence_file_name] - [-b base_address] - [-m (1=enable multicast responses,0=disable(default)] - [-z time] - [-d ] [-u directory] - [-r directory] + [-z time] 2. Optional Command-line Arguments @@ -34,23 +35,15 @@ The following describes how to run the TAO Naming Service. use of multicast. This is only used when multicast responding is enabled via '-m 1'. - -o ior_output_file - The name of the file, in which to store the IOR of the - root Naming Service context. - - -p pid_file_name - The name of the file, in which to store the process id - of the Naming Service server. - - -s context_size - Size of the hash table allocated for the root Naming - Context (if one is created). All contexts created - under the root will use the same size for their hash - tables. The default is 1024. + -b base_address + The address used for memory mapping the file specified + with the "-f" option above. The value supplied with + this option is only used when the Naming Service runs + in persistent mode, i.e., "-f" option is present. - -t time - How long (in seconds) the server should listen for - client requests before terminating. + -d + Provides Naming Service specific debug information. By default + no diagnostics are given. -f persistence_file_name The name of the file to use to store/retrieve @@ -58,12 +51,6 @@ The following describes how to run the TAO Naming Service. option, Naming Service is started in non-persistent mode. - -b base_address - The address used for memory mapping the file specified - with the "-f" option above. The value supplied with - this option is only used when the Naming Service runs - in persistent mode, i.e., "-f" option is present. - -m <0|1> TAO offers a simple, very non-standard method for clients to discover the initial reference for the @@ -74,29 +61,46 @@ The following describes how to run the TAO Naming Service. such multicast queries (use the Interoperable Naming Service bootstrap options instead). - -z time - A relative round trip timeout value (in seconds) that - the service should wait for when trying to progress an - operation through a federated naming context before - timing out and throwing a 'Cannot proceed' exception - to the client. If no value is set this will never occur. + -n number_of_threads + Specify a number of threads to be used to run the ORB. + Default is 1. - -d - Provides Naming Service specific debug information. By default - no diagnostics are given. + -o ior_output_file + The name of the file, in which to store the IOR of the + root Naming Service context. - -u directory - Use a flat-file persistence implementation that stores object - reference information in a file per context. Each context file - is placed in the directory specified. + -p pid_file_name + The name of the file, in which to store the process id + of the Naming Service server. + + -s context_size + Size of the hash table allocated for the root Naming + Context (if one is created). All contexts created + under the root will use the same size for their hash + tables. The default is 1024. + + -t time + How long (in seconds) the server should listen for + client requests before terminating. -r directory - Use redundant flat-file persistnece; same as the -u option, + Use redundant flat-file persistence; same as the -u option, except more than one instance of the TAO Naming Service server can run, each using the same set of disk files, to achieve a degree of fault tolerence (as long as directory is accessible to both servers). + -u directory + Use a flat-file persistence implementation that stores object + reference information in a file per context. Each context file + is placed in the directory specified. + + -z time + A relative round trip timeout value (in seconds) that + the service should wait for when trying to progress an + operation through a federated naming context before + timing out and throwing a 'Cannot proceed' exception + to the client. If no value is set this will never occur. 3. Environment Variables diff --git a/TAO/orbsvcs/Naming_Service/README.FT_Naming b/TAO/orbsvcs/Naming_Service/README.FT_Naming new file mode 100644 index 00000000000..c499e7198d5 --- /dev/null +++ b/TAO/orbsvcs/Naming_Service/README.FT_Naming @@ -0,0 +1,252 @@ +$Id$ + +This directory contains files that implement a server for the TAO +FT Naming Service. The FT Naming Service supports a dual redundant +scheme for fault tolerance and also implements a load balancing +mechanism when objects are bound to an object group within a named +element in the naming service. + +How to Run the TAO FT Naming Service +================================= + +1. Syntax + + % tao_ft_naming [-ORBNameServicePort nsport] + [--primary] + [--backup] + [-b base_address] + [-d debug_flag] + [-m (1=enable multicast responses,0=disable(default)] + [-n number_of_threads] + [-c ft_naming_service_ior_file] + [-g ft_naming_manager_ior_file] + [-o this_servers_object_ref_ior_file] + [-r directory_for_naming_context_replication] + [-v directory_for_object_group_replication] + [-s context_size] + [-z time] + +2. Optional Command-line Arguments + + --primary + Start this FT Naming Server in the primary role for the + dual redundant replication scheme. The primary must be + started first and then the backup. If neither primary + nor backup options are supplied, the server will run + standalone without support for fault tolerance. + + --backup + Start this FT Naming Service in the backup role for the + dual redundant replication scheme. The backup must be + started after the primary and will coordinate with the + primary to set up the notifications with the peer for + changes to the naming contexts and object groups. + + -ORBNameServicePort nsport + Multicast port for listening for requests from clients + trying to bootstrap to a Naming Service through the + use of multicast. This is only used when multicast + responding is enabled via '-m 1'. + + -b base_address + The address used for memory mapping the file specified + with the "-f" option above. The value supplied with + this option is only used when the Naming Service runs + in persistent mode, i.e., "-f" option is present. + + -d + Provides Naming Service specific debug information. By default + no diagnostics are given. + + -m <0|1> + TAO offers a simple, very non-standard method for + clients to discover the initial reference for the + Naming Service. However, since it can be inadequate and cause + unexpected results if, for example, there are multiple + naming services running on the network, the DEFAULT + behavior is for the Naming Service to NOT RESPOND to + such multicast queries (use the Interoperable Naming + Service bootstrap options instead). The multicast option + only works with for standalone servers and fault tolerance + will not be supported by the server when started with this + option. + + -n number_of_threads + Specify a number of threads to be used to run the ORB. + Default is 1. + + -c ns_ior_output_file + The name of the file, in which to store the IOR containing + the profiles for both this naming servers root naming + context and the peer naming service root naming context. + This option should only be used for the --backup naming + service. + + -g nm_ior_output_file + The name of the file, in which to store the IOR containing + the profiles for both this naming manager and the peer naming + manager. This option should only be used for the --backup + naming service. + + -h nm_ior_output_file + The name of the file, in wich to store the IOR of the + naming manager for just this service. This option can + be useful for testing. + + -o ior_output_file + The name of the file, in which to store the IOR of the + root Naming Service context for just this server. This + option is useful if you want to run the naming service + standalone, without the backup and need to obtain the + IOR of the root context implemented by this process. + + -p pid_file_name + The name of the file, in which to store the process id + of the Naming Service server. + + -s context_size + Size of the hash table allocated for the root Naming + Context (if one is created). All contexts created + under the root will use the same size for their hash + tables. The default is 1024. + + -t time + How long (in seconds) the server should listen for + client requests before terminating. + + -f persistence_file_name + The name of the file to use to store/retrieve + persistent state of the Naming Service. + + -r directory + Use redundant flat-file persistence; same as the -u option, + except more than one instance of the TAO Naming Service server + can run, each using the same set of disk files, to achieve a + degree of fault tolerence (as long as directory is accessible + to both servers). Make sure you start the --primary and --backup + with the same directory so they will share the persistence + directory. + + -u directory + Use a flat-file persistence implementation that stores object + reference information in a file per context. Each context file + is placed in the directory specified. This option can be used + when running the FT Naming Service standalone - without + fault tolerance/redundancyl. + + -v directory + Use redundant flat-file persistence for naming contexts that + are created within this server. Users can add object to the + object group and bind the object group to a name within the + naming service to obtain a load balancing capability. + Make sure you start the --primary and --backup + with the same directory so they will share the persistence + directory. + + -z time + A relative round trip timeout value (in seconds) that + the service should wait for when trying to progress an + operation through a federated naming context before + timing out and throwing a 'Cannot proceed' exception + to the client. If no value is set this will never occur. + +3. Environment Variables + + NameServicePort + Multicast port for listening for requests from clients + trying to bootstrap to a Naming Service through the + use of multicast. This is only used when multicast + responding is enabled via '-m 1'. + +4. Persistence + + When running as a fault tolerant service, the TAO FT Naming Service + uses flat file persistence. It may also be run with no persistence, + however, upon the failure of the process, no state will be saved + and it will not provide the dual-redundant fault-tolerance capability. + + 1. If the specified persistence directories for naming context + data and object group data do not exist, the server will exit. + + 2. If the specified file exists, it is scanned and: + + a) If any inconsistency is detected in the stored + state, or the file is not recognized by the Naming + Service, the server exits. (This may happen, for + example, if a server or host crashed in the middle of + writing a record to this file on a previous run). A + noncorrupted version of the file must be used instead. + + b) If the file is recognized and is ok, the state + stored in the file becomes the current state of the + Naming Service. + +5. Implementation Policies + + a. No support for BindingIterators + + With the use of redundancy between a pair of naming + servers, there is no way to guarantee that the context + structure being iterated on would remain consistent, + so the user must ensure that when invoking the list + operation that a 'how_many' value must be provided that + is sufficiently large to hold all returned bindings in + a BindingList with no BindingIterator being needed. If + the 'how_many' parameter is insufficiently large, the + FT Naming Service will throw a CORBA::NO_IMPLEMENT + exception. + + b. Dealing with orphaned contexts + + This implementation of the Naming Service does not + include any form of 'garbage collection' for orphaned + naming contexts. It is solely the responsibility of + clients to clean up after themselves and not leak + server resources. All the resources, including + orphaned contexts, are released during the Naming + Server shutdown. + +6. Clients: ways to bootstrap to the Naming Service: + + There are several methods for a client to bootstrap to a + Naming Service, i.e., there are several mechanisms + <resolve_initial_references> can use when asked for + "NameService". In order of predictable behavior, they are: + + 1. Command-line options + + The "-ORBInitRef NameService=IOR:..." or environment + variable NameServiceIOR can be used on the client side + to specify the object that the call to + <resolve_initial_references> should return to the + client. (On the server side, -c option can be used in + the backup Naming Service to write the ior). + + Example (Unix, same host): + + % $TAO_ROOT/orbsvcs/Naming_Service/Naming_Service + -r NameService -v ObjectGroups --primary + % $TAO_ROOT/orbsvcs/Naming_Service/Naming_Service + -r NameService -v ObjectGroups -c ns_ior_file --backup + % my_client -ORBInitRef NameService=file://ns_ior_file + + On the first line, we start the primary Naming + Service. On the second line we start the backup + Naming Service and output the multi-profile IOR to + to <ns_ior_file>. On the third line, we start + some client, and specify the ior + <resolve_initial_references> should return for + the Naming Service in a file format. + + +Troubleshooting +============================================ + +Q1. Error Message: "Invalid persistence directory" or "Invalid object +group persistence directory" + +A1. On starting, the error message "Invalid persistence directory" +indicates that the supplied value for the -r option does not point +to a directory that can be used to store the state of the naming contexts +or object groups. Make sure that the provided directories exist and +that they are write enabled. diff --git a/TAO/orbsvcs/orbsvcs/CosEvent.mpc b/TAO/orbsvcs/orbsvcs/CosEvent.mpc index 80efa635a0a..97b0de957d9 100644 --- a/TAO/orbsvcs/orbsvcs/CosEvent.mpc +++ b/TAO/orbsvcs/orbsvcs/CosEvent.mpc @@ -84,7 +84,7 @@ project (CosEvent_Skel) : orbsvcslib, orbsvcs_output, install, avoids_minimum_co } -project (CosEvent_Serv) : orbsvcslib, orbsvcs_output, install, avoids_minimum_corba, event_skel, ec_typed_events_serv, messaging_optional, naming, svc_utils { +project (CosEvent_Serv) : orbsvcslib, orbsvcs_output, install, avoids_minimum_corba, event_skel, ec_typed_events_serv, messaging_optional, ifr_client, naming, svc_utils { sharedname = TAO_CosEvent_Serv dynamicflags += TAO_EVENT_SERV_BUILD_DLL tagchecks += CosEvent diff --git a/TAO/orbsvcs/orbsvcs/CosNaming_Serv.mpc b/TAO/orbsvcs/orbsvcs/CosNaming_Serv.mpc index 9e683abb6d9..9cd821e7bf3 100644 --- a/TAO/orbsvcs/orbsvcs/CosNaming_Serv.mpc +++ b/TAO/orbsvcs/orbsvcs/CosNaming_Serv.mpc @@ -17,6 +17,7 @@ project(CosNaming_Serv) : cosnaming_serv_persistence, orbsvcslib, orbsvcs_output Naming/Naming_Context_Interface.cpp Naming/Naming_Loader.cpp Naming/Naming_Server.cpp + Naming/Storable_Naming_Context_Factory.cpp Naming/Transient_Naming_Context.cpp } } diff --git a/TAO/orbsvcs/orbsvcs/FT_NamingManager.idl b/TAO/orbsvcs/orbsvcs/FT_NamingManager.idl new file mode 100644 index 00000000000..ae13105d9aa --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/FT_NamingManager.idl @@ -0,0 +1,63 @@ +/* -*- IDL -*- */ +//============================================================================= +/** + * @file FT_NamingManager.idl + * + * $Id$ + * + * This file is part of Fault Tolerant Naming Service. + * + * @author Kevin Stanley <stanleyk@ociweb.com> + */ +//============================================================================= + +#ifndef _FT_NAMING_MANAGER_IDL_ +#define _FT_NAMING_MANAGER_IDL_ + +#include "orbsvcs/PortableGroup.idl" + +module FT_Naming +{ + typedef PortableGroup::ObjectGroup ObjectGroup; + + const string TAO_FT_OBJECT_GROUP_NAME = "TAO_FT_GroupName"; + const string TAO_FT_LOAD_BALANCING_STRATEGY = "TAO_FT_LB_Strategy"; + + typedef long LoadBalancingStrategyValue; + const LoadBalancingStrategyValue ROUND_ROBIN = 0; + const LoadBalancingStrategyValue RANDOM = 1; + const LoadBalancingStrategyValue LEAST = 2; + + typedef string GroupName; + typedef sequence<string> GroupNames; + + // Specification of NamingManager Interface + interface NamingManager : PortableGroup::PropertyManager, + PortableGroup::ObjectGroupManager + { + ObjectGroup create_object_group (in GroupName group_name, + in LoadBalancingStrategyValue lb_strategy, + in PortableGroup::Criteria the_criteria) + raises (PortableGroup::ObjectNotCreated, + PortableGroup::InvalidCriteria, + PortableGroup::InvalidProperty, + PortableGroup::CannotMeetCriteria); + + void delete_object_group (in string group_name) + raises (PortableGroup::ObjectGroupNotFound); + + ObjectGroup get_object_group_ref_from_name ( + in string group_name) + raises (PortableGroup::ObjectGroupNotFound); + + void set_load_balancing_strategy (in string group_name, + in LoadBalancingStrategyValue lb_strategy); + + // Return names of all groups defined in the NamingManager + GroupNames groups (in LoadBalancingStrategyValue target_stategy); + + }; +}; + + +#endif // _FT_NAMING_MANAGER_IDL_ diff --git a/TAO/orbsvcs/orbsvcs/FT_NamingReplication.idl b/TAO/orbsvcs/orbsvcs/FT_NamingReplication.idl new file mode 100644 index 00000000000..df1c1178422 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/FT_NamingReplication.idl @@ -0,0 +1,79 @@ +/* -*- IDL -*- */ +//============================================================================= +/** + * @file FT_NamingReplication.idl + * + * $Id$ + * + * This file is part of Fault Tolerant Naming Service in support of + * replication between redundant servers. + * + * @author Kevin Stanley <stanleyk@ociweb.com> + */ +//============================================================================= + +#ifndef _FT_NAMING_REPLICATION_IDL_ +#define _FT_NAMING_REPLICATION_IDL_ + +#include <orbsvcs/CosNaming.idl> +#include <orbsvcs/FT_NamingManager.idl> +#include <orbsvcs/FT_CORBA_ORB.idl> + +module FT_Naming +{ + + enum ChangeType { NEW, UPDATED, DELETED }; + + exception NotAvailable + { + }; + + /* + * A structure that describes the updated element in a Naming Service + */ + struct NamingContextUpdate + { + /// The name of context being updated + string context_name; + /// The type of change that is being reported + ChangeType change_type; + }; + + struct ReplicaInfo + { + CosNaming::NamingContext root_context; + FT_Naming::NamingManager naming_manager; + }; + + /* + * A structure that describes the updated element within + * an Object Group Manager + */ + struct ObjectGroupUpdate + { + /// This is used to identify object group references. + PortableGroup::ObjectGroupId id; + /// The type of change that is being reported + ChangeType change_type; + }; + + interface ReplicationManager + { + /* + * Register with a peer replica providing an object reference for + * notification of updates. Each replica will maintain their state + * in a shared repository and the update notification indicates the + * element that was changed. + */ + ReplicaInfo register_replica (in ReplicationManager replica, + in ReplicaInfo replica_info) + raises (NotAvailable); + + oneway void notify_updated_object_group(in ObjectGroupUpdate group_info); + + oneway void notify_updated_context(in NamingContextUpdate context_info); + }; +}; + + +#endif // _FT_NAMING_REPLICATION_IDL_ diff --git a/TAO/orbsvcs/orbsvcs/FT_Naming_Serv.mpc b/TAO/orbsvcs/orbsvcs/FT_Naming_Serv.mpc new file mode 100644 index 00000000000..6f963a8f725 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/FT_Naming_Serv.mpc @@ -0,0 +1,42 @@ +// -*- MPC -*- +// $Id$ + +project (FT_Naming_Serv) : orbsvcslib, orbsvcs_output, ftnaming, ftnaming_replication, install, naming_serv, naming, portablegroup, avoids_minimum_corba { + sharedname = TAO_FT_Naming_Serv + idlflags += -Wb,export_macro=TAO_FtNaming_Export -Wb,export_include=orbsvcs/Naming/FaultTolerant/ftnaming_export.h + dynamicflags += TAO_FTNAMING_BUILD_DLL + tagchecks += FaultTolerantNaming + + IDL_Files { + } + + Source_Files (ORBSVCS_COMPONENTS) { + Naming/FaultTolerant/FT_Naming_Manager.cpp + Naming/FaultTolerant/FT_Naming_Replication_Manager.cpp + Naming/FaultTolerant/FT_Naming_Server.cpp + Naming/FaultTolerant/FT_Persistent_Naming_Context.cpp + Naming/FaultTolerant/FT_Persistent_Naming_Context_Factory.cpp + Naming/FaultTolerant/FT_Round_Robin.cpp + Naming/FaultTolerant/FT_Storable_Naming_Context.cpp + Naming/FaultTolerant/FT_Storable_Naming_Context_Factory.cpp + Naming/FaultTolerant/FT_PG_Object_Group_Storable.cpp + Naming/FaultTolerant/FT_PG_Group_Factory.cpp + } + + Header_Files { + Naming/FaultTolerant/FT_Naming_Manager.h + Naming/FaultTolerant/FT_Naming_Replication_Manager.h + Naming/FaultTolerant/FT_Naming_Server.h + Naming/FaultTolerant/FT_Persistent_Naming_Context.h + Naming/FaultTolerant/FT_Persistent_Naming_Context_Factory.h + Naming/FaultTolerant/FT_Round_Robin.h + Naming/FaultTolerant/FT_Storable_Naming_Context.h + Naming/FaultTolerant/FT_Storable_Naming_Context_Factory.h + Naming/FaultTolerant/FT_PG_Object_Group_Storable.h + Naming/FaultTolerant/FT_PG_Group_Factory.h + Naming/FaultTolerant/ftnaming_export.h + Naming/FaultTolerant/ftnaming_intf_export.h + } + +} + diff --git a/TAO/orbsvcs/orbsvcs/FtNaming.mpc b/TAO/orbsvcs/orbsvcs/FtNaming.mpc new file mode 100644 index 00000000000..c36764fa984 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/FtNaming.mpc @@ -0,0 +1,28 @@ +// -*- MPC -*- +// $Id$ + +project (FtNaming) : orbsvcslib, orbsvcs_output, install, naming_serv, portablegroup, avoids_minimum_corba { + sharedname = TAO_FtNaming + idlflags += -Wb,export_macro=TAO_FtNaming_Intf_Export \ + -Wb,export_include=orbsvcs/Naming/FaultTolerant/ftnaming_intf_export.h + dynamicflags += TAO_FTNAMING_INTF_BUILD_DLL + tagchecks += FtNaming + + IDL_Files { + idlflags += -GC + FT_NamingManager.idl + } + + Source_Files (ORBSVCS_COMPONENTS) { + FT_NamingManagerC.cpp + FT_NamingManagerS.cpp + Naming/FaultTolerant/nsgroup_svc.cpp + } + + Header_Files { + FT_NamingManagerC.h + FT_NamingManagerS.h + Naming/FaultTolerant/nsgroup_svc.h + } +} + diff --git a/TAO/orbsvcs/orbsvcs/FtNamingReplication.mpc b/TAO/orbsvcs/orbsvcs/FtNamingReplication.mpc new file mode 100644 index 00000000000..cb329f671ca --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/FtNamingReplication.mpc @@ -0,0 +1,25 @@ +// -*- MPC -*- +// $Id$ + +project (FtNamingReplication) : ftnaming, orbsvcslib, orbsvcs_output, install, naming_serv, portablegroup, avoids_minimum_corba { + sharedname = TAO_FtNamingReplication + idlflags += -Wb,export_macro=TAO_FtNaming_Export -Wb,export_include=orbsvcs/Naming/FaultTolerant/ftnaming_export.h + dynamicflags += TAO_FTNAMING_BUILD_DLL + + IDL_Files { + idlflags += -GC + FT_NamingReplication.idl + } + + Source_Files (ORBSVCS_COMPONENTS) { + FT_NamingReplicationC.cpp + FT_NamingReplicationS.cpp + } + + Header_Files { + FT_NamingReplicationC.h + FT_NamingReplicationS.h + } + +} + diff --git a/TAO/orbsvcs/orbsvcs/FtRtEvent/Utils/FTEC_Gateway.cpp b/TAO/orbsvcs/orbsvcs/FtRtEvent/Utils/FTEC_Gateway.cpp index f6592820c0f..18e2bb69a54 100644 --- a/TAO/orbsvcs/orbsvcs/FtRtEvent/Utils/FTEC_Gateway.cpp +++ b/TAO/orbsvcs/orbsvcs/FtRtEvent/Utils/FTEC_Gateway.cpp @@ -242,7 +242,7 @@ void FTEC_Gateway::remove_observer (RtecEventChannelAdmin::Observer_Handle handl void FTEC_Gateway::push(RtecEventChannelAdmin::ProxyPushConsumer_ptr proxy_consumer, const RtecEventComm::EventSet & data) { - PortableServer::ObjectId_var object_id = + const PortableServer::ObjectId_var object_id = impl_->poa->reference_to_id(proxy_consumer); FtRtecEventComm::ObjectId** result; ACE_OS::memcpy(&result, &object_id[0], sizeof(FtRtecEventComm::ObjectId**)); @@ -315,9 +315,9 @@ get_remote_oid_ptr(CORBA::ORB_ptr orb) { PortableServer::Current_var current = resolve_init<PortableServer::Current>(orb, - "POACurrent"); + "POACurrent"); - PortableServer::ObjectId_var object_id = + const PortableServer::ObjectId_var object_id = current->get_object_id(); FtRtecEventComm::ObjectId** result; diff --git a/TAO/orbsvcs/orbsvcs/HTIOP/HTIOP_Profile.cpp b/TAO/orbsvcs/orbsvcs/HTIOP/HTIOP_Profile.cpp index b69a58ea11e..cb65c9c3a69 100644 --- a/TAO/orbsvcs/orbsvcs/HTIOP/HTIOP_Profile.cpp +++ b/TAO/orbsvcs/orbsvcs/HTIOP/HTIOP_Profile.cpp @@ -279,7 +279,7 @@ TAO::HTIOP::Profile::add_endpoint (TAO::HTIOP::Endpoint *endp) } char * -TAO::HTIOP::Profile::to_string (void) +TAO::HTIOP::Profile::to_string (void) const { CORBA::String_var key; TAO::ObjectKey::encode_sequence_to_string (key.inout(), diff --git a/TAO/orbsvcs/orbsvcs/HTIOP/HTIOP_Profile.h b/TAO/orbsvcs/orbsvcs/HTIOP/HTIOP_Profile.h index ef0dc3fa9dc..f292660153d 100644 --- a/TAO/orbsvcs/orbsvcs/HTIOP/HTIOP_Profile.h +++ b/TAO/orbsvcs/orbsvcs/HTIOP/HTIOP_Profile.h @@ -88,7 +88,7 @@ namespace TAO * This is used to create url-style reference. Only one * endpoint is included into the string. */ - virtual char * to_string (void); + virtual char * to_string (void) const; /** * Endpoints are transmitted using TAO-proprietory tagged component. diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.cpp index b14c5612c23..0ba928de2fe 100644 --- a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.cpp +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LeastLoaded.cpp @@ -155,7 +155,7 @@ TAO_LB_LeastLoaded::get_loads (CosLoadBalancing::LoadManager_ptr load_manager, this->push_loads (the_location, loads.in (), - loads[0]); + loads.inout ()[0]); return loads._retn (); } diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.cpp index 56b5157d4a7..463f4c3da83 100644 --- a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.cpp +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadAverage.cpp @@ -153,7 +153,7 @@ TAO_LB_LoadAverage::get_loads (CosLoadBalancing::LoadManager_ptr load_manager, this->push_loads (the_location, loads.in (), - loads[0]); + loads.inout ()[0]); return loads._retn (); } diff --git a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.cpp b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.cpp index 90dd6c015e4..6f2e8a65abf 100644 --- a/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.cpp +++ b/TAO/orbsvcs/orbsvcs/LoadBalancing/LB_LoadMinimum.cpp @@ -154,7 +154,7 @@ TAO_LB_LoadMinimum::get_loads (CosLoadBalancing::LoadManager_ptr load_manager, this->push_loads (the_location, loads.in (), - loads[0]); + loads.inout ()[0]); return loads._retn (); } diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Location_Index_Map.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Location_Index_Map.h new file mode 100644 index 00000000000..fa1fe4e3cee --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Location_Index_Map.h @@ -0,0 +1,42 @@ +// -*- C++ -*- + +//======================================================================= +/** + * @file FT_Location_Index_Map.h + * + * $Id$ + * + * @author Kevin Stanley <stanleyk@ociweb.com> + */ +//======================================================================= + + +#ifndef TAO_FT_LOCATION_INDEX_MAP_H +#define TAO_FT_LOCATION_INDEX_MAP_H + +#include /**/ "ace/pre.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "orbsvcs/PortableGroupC.h" + +#include "ace/Functor.h" +#include "ace/Hash_Map_Manager_T.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +/// Location index map. +typedef ACE_Hash_Map_Manager_Ex< + PortableGroup::ObjectGroupId, + CORBA::ULong, + ACE_Hash<ACE_UINT64>, + ACE_Equal_To<ACE_UINT64>, + ACE_Null_Mutex> TAO_FT_Location_Index_Map; + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* TAO_FT_LOCATION_INDEX_MAP_H */ diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.cpp b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.cpp new file mode 100644 index 00000000000..011f25b2190 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.cpp @@ -0,0 +1,747 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_Naming_Manager.cpp + * + * $Id$ + * + * @author Kevin Stanley <stanleyk@ociweb.com> + */ +//============================================================================= + +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.h" +#include "orbsvcs/FT_NamingManagerC.h" +#include "orbsvcs/PortableGroup/PG_Property_Utils.h" +#include "orbsvcs/PortableGroup/PG_Property_Set.h" +#include "orbsvcs/PortableGroup/PG_Object_Group.h" +#include "orbsvcs/PortableGroup/PG_conf.h" +#include "orbsvcs/PortableGroup/PG_Utils.h" + +#include "tao/debug.h" +#include "tao/ORB_Constants.h" + +#include "ace/SString.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" + +// Use this macro at the beginning of CORBA methods +// to aid in debugging. +#define METHOD_ENTRY(name) \ + if (TAO_debug_level > 6) \ + { \ + ACE_DEBUG (( LM_DEBUG, \ + "Enter %s\n", #name \ + )); \ + } + +// Use this macro to return from CORBA methods +// to aid in debugging. Note that you can specify +// the return value after the macro, for example: +// METHOD_RETURN(Plugh::plover) xyzzy; is equivalent +// to return xyzzy; +// METHOD_RETURN(Plugh::troll); is equivalent to +// return; +// WARNING: THIS GENERATES TWO STATEMENTS!!! THE FOLLOWING +// will not do what you want it to: +// if (cave_is_closing) METHOD_RETURN(Plugh::pirate) aarrggh; +// Moral: Always use braces. +#define METHOD_RETURN(name) \ + if (TAO_debug_level > 6) \ + { \ + ACE_DEBUG (( LM_DEBUG, \ + "Leave %s\n", #name \ + )); \ + } \ + return /* value goes here */ + + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +TAO_FT_Naming_Manager::TAO_FT_Naming_Manager (void) + : factory_registry_ ("NamingManager::FactoryRegistry"), + group_factory_ (), + built_in_balancing_strategy_name_ (1), + object_group_property_name_ (1) + +{ + // The name for the property which contains the load balancing strategy value + this->built_in_balancing_strategy_name_.length (1); + this->built_in_balancing_strategy_name_[0].id = + FT_Naming::TAO_FT_LOAD_BALANCING_STRATEGY; + + // The name for the property which contains the object group name + this->object_group_property_name_.length (1); + this->object_group_property_name_[0].id = + FT_Naming::TAO_FT_OBJECT_GROUP_NAME; +} + +TAO_FT_Naming_Manager::~TAO_FT_Naming_Manager (void) +{ + this->object_group_property_name_.length (0); + this->built_in_balancing_strategy_name_.length (0); +} + + +CORBA::Object_ptr +TAO_FT_Naming_Manager::create_object_group ( + const char * group_name, + FT_Naming::LoadBalancingStrategyValue lb_strategy, + const ::PortableGroup::Criteria & the_criteria) +{ + // The when creating the object group, it starts as a generic + // CORBA Object. It will become the type of the first added + // member. + const char * type_id = ACE_TEXT ("IDL:omg.org:CORBA/Object:1.0"); + + // Add the group name to the criteria and create the object + TAO::PG_Property_Set property_set (the_criteria); + PortableGroup::Value value; + value <<= group_name; + property_set.set_property (FT_Naming::TAO_FT_OBJECT_GROUP_NAME, value); + + // Add the load balancing strategy to the properties + value <<= lb_strategy; + property_set.set_property (FT_Naming::TAO_FT_LOAD_BALANCING_STRATEGY, value); + + PortableGroup::Criteria new_criteria; + property_set.export_properties (new_criteria); + PortableGroup::GenericFactory::FactoryCreationId_var fcid; + + return this->create_object (group_name, type_id, new_criteria, fcid.out()); +} + +void +TAO_FT_Naming_Manager::delete_object_group (const char * group_name) +{ + // Find the object group with the specified name and delete the object + PortableGroup::ObjectGroup_var group = + this->get_object_group_ref_from_name (group_name); + + if (!CORBA::is_nil (group.in())) + { + PortableGroup::ObjectGroupId group_id = + this->get_object_group_id (group); + + // Delete the object group from the factory + this->group_factory_.delete_group (group_id); + } + else + { + throw PortableGroup::ObjectGroupNotFound (); + } + +} + +PortableGroup::ObjectGroup_ptr +TAO_FT_Naming_Manager::get_object_group_ref_from_name (const char * group_name) +{ + TAO::PG_Object_Group* group; + if (this->group_factory_.find_group_with_name (group_name, group)) + { + return group->reference (); + } + else + { + throw PortableGroup::ObjectGroupNotFound (); + } +} + +::FT_Naming::GroupNames * +TAO_FT_Naming_Manager::groups (::FT_Naming::LoadBalancingStrategyValue target_strategy) +{ + PortableGroup::ObjectGroups_var all_groups = this->group_factory_.all_groups (); + int num_groups = all_groups->length (); + + FT_Naming::GroupNames* group_names; + ACE_NEW_THROW_EX ( + group_names, + FT_Naming::GroupNames (num_groups), + CORBA::NO_MEMORY()); + + int matching_groups = 0; + for (int i = 0; i < num_groups; ++i) + { + PortableGroup::ObjectGroup_var obj_group = (all_groups.in ())[i].in (); + + // Extract the group's Load Balancing property + PortableGroup::Name lb_strat_property_name (1); + lb_strat_property_name.length (1); + lb_strat_property_name[0].id = CORBA::string_dup (::FT_Naming::TAO_FT_LOAD_BALANCING_STRATEGY); + PortableGroup::Properties_var props = this->get_properties (obj_group); + PortableGroup::Value value; + TAO_PG::get_property_value (lb_strat_property_name, props.in (), value); + ::FT_Naming::LoadBalancingStrategyValue lb_strategy_val; + value >>= lb_strategy_val; + + if (lb_strategy_val == target_strategy) + { // Groups load balancing strategy matches the target + // Increment the count of matching groups + ++matching_groups; + char* name; + + // Get the group name and add it to the list to return. + if (this->group_name (obj_group.in (), name)) + { // Group does have a name + group_names->length (matching_groups); + (*group_names)[matching_groups-1] = name; + } + else + { + { // Group has no name + (*group_names)[i] = CORBA::string_dup ("<unnamed group>"); + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%T %n (%P|%t) - FT_Naming_Manager::groups: no name ") + ACE_TEXT ("property set on group.\n") + )); + } + } + } + } + // Set the length to the actual num added + group_names->length (matching_groups); + return group_names; +} + +void +TAO_FT_Naming_Manager::set_load_balancing_strategy ( + const char * group_name, + ::FT_Naming::LoadBalancingStrategyValue lb_strategy) +{ + CORBA::Object_var group = this->get_object_group_ref_from_name (group_name); + + TAO::PG_Property_Set property_set; + PortableGroup::Value value; + // Add the load balancing strategy to the properties + value <<= lb_strategy; + property_set.set_property (FT_Naming::TAO_FT_LOAD_BALANCING_STRATEGY, value); + PortableGroup::Properties properties; + property_set.export_properties (properties); + this->set_properties_dynamically (group, properties); +} + + +bool +TAO_FT_Naming_Manager::group_name (PortableGroup::ObjectGroup_ptr group, + char*& name) +{ + if (CORBA::is_nil (group)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%T %n (%P|%t) - FT_Naming_Manager::group_name: ") + ACE_TEXT ("cannot get name for a null object.\n") + )); + return false; + } + + TAO::PG_Object_Group* pg_group; + if (this->group_factory_.find_group (group, pg_group)) + { // Found the object group in the factory + const char* grp_name = pg_group->get_name (); + if (grp_name != 0) + { // Valid group name defined + name = CORBA::string_dup (grp_name); + return true; + } + else + { // The group has no name + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("TAO_FT_Naming_Manager::group_name - ") + ACE_TEXT ("object group does not have a name")), + false); + } + } + else + { // The factory does not know about the group + return false; + } +} + +void +TAO_FT_Naming_Manager::set_default_properties ( + const PortableGroup::Properties & props) +{ + + this->properties_support_.set_default_properties (props); + //@@ validate properties? +} + +PortableGroup::Properties * +TAO_FT_Naming_Manager::get_default_properties () +{ + return this->properties_support_.get_default_properties (); +} + +void +TAO_FT_Naming_Manager::remove_default_properties ( + const PortableGroup::Properties & props) +{ + this->properties_support_.remove_default_properties (props); +} + +void +TAO_FT_Naming_Manager::set_type_properties ( + const char *type_id, + const PortableGroup::Properties & overrides) +{ + this->properties_support_.set_type_properties ( + type_id, + overrides); +} + +PortableGroup::Properties * +TAO_FT_Naming_Manager::get_type_properties ( + const char *type_id) +{ + return this->properties_support_.get_type_properties (type_id); +} + +void +TAO_FT_Naming_Manager::remove_type_properties ( + const char *type_id, + const PortableGroup::Properties & props) +{ + this->properties_support_.remove_type_properties ( + type_id, + props); +} + +void +TAO_FT_Naming_Manager::set_properties_dynamically ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Properties & overrides) +{ + + TAO::PG_Object_Group * group = 0; + if (this->group_factory_.find_group (object_group, group)) + { + group->set_properties_dynamically (overrides); + } + else + { + throw PortableGroup::ObjectGroupNotFound (); + } +} + +PortableGroup::Properties * +TAO_FT_Naming_Manager::get_properties ( + PortableGroup::ObjectGroup_ptr object_group) +{ + PortableGroup::Properties_var result; + ACE_NEW_THROW_EX (result, PortableGroup::Properties(), CORBA::NO_MEMORY ()); + + TAO::PG_Object_Group * group = 0; + if (this->group_factory_.find_group (object_group, group)) + { + group->get_properties (result); + } + else + { + throw PortableGroup::ObjectGroupNotFound (); + } + return result._retn(); +} + +PortableGroup::ObjectGroup_ptr +TAO_FT_Naming_Manager::create_member ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location, + const char * type_id, + const PortableGroup::Criteria & the_criteria) +{ + PortableGroup::ObjectGroup_var result = PortableGroup::ObjectGroup::_nil(); + TAO::PG_Object_Group * group = 0; + if (this->group_factory_.find_group (object_group, group)) + { + group->create_member (the_location, type_id, the_criteria); + result = group->reference (); + } + else + { + if (TAO_debug_level > 0) + { + ACE_ERROR ( (LM_ERROR, + ACE_TEXT ("%T %n (%P|%t) - FT_Naming_Manager::create_member: ") + ACE_TEXT ("unknown group\n") + )); + } + throw PortableGroup::ObjectGroupNotFound (); + } + return result._retn(); +} + +PortableGroup::ObjectGroup_ptr +TAO_FT_Naming_Manager::add_member ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location, + CORBA::Object_ptr member) +{ + METHOD_ENTRY (TAO::FT_Naming_Manager::add_member); + PortableGroup::ObjectGroup_var result = PortableGroup::ObjectGroup::_nil (); + + // Find the object group corresponding to this IOGR + TAO::PG_Object_Group * group = 0; + if (this->group_factory_.find_group (object_group, group)) + { + try { + + group->add_member (the_location, + member); + } + catch (...) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("TAO_FT_Naming_Manager::add_member - ") + ACE_TEXT ("Issue with IOR of group or member.\n"))); + throw PortableGroup::ObjectNotAdded (); + } + + result = group->reference (); + + } + else + { + if (TAO_debug_level > 0) + { + ACE_ERROR ( (LM_ERROR, + ACE_TEXT ("%T %n (%P|%t) - FT_Naming_Manager::add_member ") + ACE_TEXT ("to unknown group\n") + )); + } + throw PortableGroup::ObjectGroupNotFound (); + } + METHOD_RETURN (TAO::FT_Naming_Manager::add_member) result._retn (); +} + + +PortableGroup::ObjectGroup_ptr +TAO_FT_Naming_Manager::remove_member ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location) +{ + PortableGroup::ObjectGroup_var result = PortableGroup::ObjectGroup::_nil (); + + // Find the object group corresponding to this IOGR + TAO::PG_Object_Group * group = 0; + if (this->group_factory_.find_group (object_group, group)) + { + group->remove_member (the_location); + + group->minimum_populate (); + //@@ how about the case where the member was removed successfully, + // but for one reason or another we were unable to bring the group + // back up to minimum_number_of_replicas? + + result = group->reference (); + } + else + { + throw PortableGroup::ObjectGroupNotFound (); + } + return result._retn (); +} + + +PortableGroup::Locations * +TAO_FT_Naming_Manager::locations_of_members ( + PortableGroup::ObjectGroup_ptr object_group) +{ + PortableGroup::Locations_var result = 0; + + // Find the object group corresponding to this IOGR + TAO::PG_Object_Group * group = 0; + if (this->group_factory_.find_group (object_group, group)) + { + result = group->locations_of_members (); + } + else + { + if (TAO_debug_level > 0) + { + ACE_ERROR ( (LM_ERROR, + ACE_TEXT ("%T %n (%P|%t) - FT_Naming_Manager::") + ACE_TEXT ("locations_of_members: unknown group\n") + )); + } + throw PortableGroup::ObjectGroupNotFound (); + } + return result._retn (); +} + +PortableGroup::ObjectGroups * +TAO_FT_Naming_Manager::groups_at_location ( + const PortableGroup::Location & the_location) +{ + return this->group_factory_.groups_at_location (the_location); +} + +PortableGroup::ObjectGroupId +TAO_FT_Naming_Manager::get_object_group_id ( + PortableGroup::ObjectGroup_ptr object_group) +{ + PortableGroup::ObjectGroupId result = 0; + TAO::PG_Object_Group * group = 0; + if (this->group_factory_.find_group (object_group, group)) + { + group->get_object_group_id (); + result = group->get_object_group_id (); + } + else + { + if (TAO_debug_level > 0) + { + ACE_ERROR ( (LM_ERROR, + ACE_TEXT ("%T %n (%P|%t) - FT_Naming_Manager::") + ACE_TEXT ("get_object_group_id: unknown group\n") + )); + } + throw PortableGroup::ObjectGroupNotFound (); + } + return result; +} + +PortableGroup::ObjectGroup_ptr +TAO_FT_Naming_Manager::get_object_group_ref ( + PortableGroup::ObjectGroup_ptr object_group) +{ + PortableGroup::ObjectGroup_var result = PortableGroup::ObjectGroup::_nil (); + + // Find the object group corresponding to this IOGR + TAO::PG_Object_Group * group = 0; + if (this->group_factory_.find_group (object_group, group)) + { + result = group->reference (); + } + else + { + if (TAO_debug_level > 0) + { + ACE_ERROR ( (LM_ERROR, + ACE_TEXT ("%T %n (%P|%t) - FT_Naming_Manager::") + ACE_TEXT ("get_object_group_ref: unknown group\n") + )); + } + throw PortableGroup::ObjectGroupNotFound (); + } + return result._retn(); +} + +PortableGroup::ObjectGroup_ptr TAO_FT_Naming_Manager::get_object_group_ref_from_id ( + PortableGroup::ObjectGroupId group_id) +{ + PortableGroup::ObjectGroup_var result = PortableGroup::ObjectGroup::_nil (); + + // Find the object group corresponding to this IOGR + TAO::PG_Object_Group * group = 0; + if (this->group_factory_.find_group (group_id, group)) + { + result = group->reference (); + } + else + { + if (TAO_debug_level > 0) + { + ACE_ERROR ( (LM_ERROR, + ACE_TEXT ("%T %n (%P|%t) - FT_Naming_Manager::") + ACE_TEXT ("get_object_group_ref_from_id: unknown group\n") + )); + } + throw PortableGroup::ObjectGroupNotFound (); + } + return result._retn(); +} + +CORBA::Object_ptr +TAO_FT_Naming_Manager::get_member_ref ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location) +{ + CORBA::Object_var result = CORBA::Object::_nil(); + + // Find the object group corresponding to this IOGR + TAO::PG_Object_Group * group = 0; + if (this->group_factory_.find_group (object_group, group)) + { + result = group->get_member_reference (the_location); + } + else + { + if (TAO_debug_level > 0) + { + ACE_ERROR ( (LM_ERROR, + ACE_TEXT ("%T %n (%P|%t) - FT_Naming_Manager::") + ACE_TEXT ("get_member_ref: unknown group\n") + )); + } + throw PortableGroup::ObjectGroupNotFound (); + } + return result._retn(); +} + +CORBA::Object_ptr +TAO_FT_Naming_Manager::create_object ( + const char * object_name, + const char * type_id, + const PortableGroup::Criteria & the_criteria, + PortableGroup::GenericFactory::FactoryCreationId_out + factory_creation_id) +{ + METHOD_ENTRY (TAO::FT_Naming_Manager::create_object); + + //////////////////////////////// + // find the properties for this + // type of object group + ACE_Auto_Ptr<TAO::PG_Property_Set> typeid_properties + (this->properties_support_.find_typeid_properties (type_id)); + + TAO::PG_Object_Group * group + = this->group_factory_.create_group ( + type_id, + the_criteria, + typeid_properties.get ()); + + // The group now owns the properties. + typeid_properties.release (); + + group->set_name (object_name); + + // Dont distribute the object group for its usage in the FT_Naming_Manager + group->distribute (0); + + group->initial_populate (); + //@@ on error we should remove the group from the Group_Factory + // doing this "right" will require a var-type pointer to the object group + // that knows about the factory, too. + + // Allocate a new FactoryCreationId for use as an "out" parameter. + PortableGroup::GenericFactory::FactoryCreationId_ptr factory_id_ptr = 0; + ACE_NEW_THROW_EX (factory_id_ptr, + PortableGroup::GenericFactory::FactoryCreationId, + CORBA::NO_MEMORY ( + CORBA::SystemException::_tao_minor_code ( + TAO::VMCID, + ENOMEM), + CORBA::COMPLETED_NO)); + PortableGroup::GenericFactory::FactoryCreationId_var factory_id = factory_id_ptr; + PortableGroup::ObjectGroupId group_id = group->get_object_group_id (); + factory_id <<= group_id; + factory_creation_id = factory_id._retn(); + + METHOD_RETURN (TAO::FT_Naming_Manager::create_object) group->reference (); +} + +void +TAO_FT_Naming_Manager::delete_object ( + const PortableGroup::GenericFactory::FactoryCreationId & + factory_creation_id) +{ + + PortableGroup::ObjectGroupId group_id = 0; + if (factory_creation_id >>= group_id) + { + this->group_factory_.delete_group ( + group_id); + } + else + { + throw PortableGroup::ObjectNotFound (); + } +} + +void +TAO_FT_Naming_Manager::initialize (CORBA::ORB_ptr orb, + PortableServer::POA_ptr naming_mgr_poa) +{ + ACE_GUARD (TAO_SYNCH_MUTEX, + guard, + this->lock_); + + // Initialize the components used to implement the PortableGroup interfaces + this->factory_registry_.init (orb); + PortableGroup::FactoryRegistry_var factory_ref = + factory_registry_.reference (); + this->group_factory_.init (orb, + naming_mgr_poa, + factory_ref.in ()); +} + +CORBA::Object_ptr +TAO_FT_Naming_Manager::next_member (PortableGroup::ObjectGroup_ptr object_group) +{ + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + monitor, + this->lock_, + CORBA::Object::_nil () + ); + + ACE_Auto_Ptr<PortableGroup::Properties> props ( + this->get_properties (object_group)); + PortableGroup::Value value; + CORBA::Boolean found = + TAO_PG::get_property_value (built_in_balancing_strategy_name_, + *(props.get ()), + value); + + // If there is no TAO_FT_LOAD_BALANCING_STRATEGY property in the object group + // return failure + if (!found) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%T %n (%P|%t) - TAO_FT_Naming_Manager::next_member: ") + ACE_TEXT ("object group has no TAO_FT_LOAD_BALANCING_STRATEGY ") + ACE_TEXT ("property.\n") + )); + + return CORBA::Object::_nil(); + } + + // Extract the load balancing strategy value + FT_Naming::LoadBalancingStrategyValue load_bal_strategy; + value >>= load_bal_strategy; + + PortableGroup::Location next_location; + + bool result = false; + + switch (load_bal_strategy) + { + case FT_Naming::ROUND_ROBIN: + result = this->round_robin_.next_location (object_group, this, next_location); + break; + default: + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%T %n (%P|%t) - TAO_FT_Naming_Manager::next_location: ") + ACE_TEXT ("unsupported load balancing strategy requested.\n") + )); + + return CORBA::Object::_nil(); + break; + } + + if (result == true) + return this->get_member_ref (object_group, next_location); + else + return CORBA::Object::_nil(); +} + + +void +TAO_FT_Naming_Manager::preprocess_properties (PortableGroup::Properties &) +{ + // Nothing to do here for now. +} + +void +TAO_FT_Naming_Manager::set_object_group_storable_factory (TAO::Storable_Factory * factory) +{ + this->group_factory_.set_object_group_storable_factory (factory); +} + +void +TAO_FT_Naming_Manager::set_object_group_stale (const FT_Naming::ObjectGroupUpdate & group_info) +{ + this->group_factory_.set_object_group_stale (group_info); +} + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.h new file mode 100644 index 00000000000..97193b9d9fe --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.h @@ -0,0 +1,351 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_Naming_Manager.h + * + * $Id$ + * + * @author Kevin Stanley <stanleyk@ociweb.com> + */ +//============================================================================= + + +#ifndef TAO_FT_NAMING_MANAGER_H +#define TAO_FT_NAMING_MANAGER_H + +#include /**/ "ace/pre.h" + +#include "orbsvcs/Naming/FaultTolerant/ftnaming_export.h" + +#include "orbsvcs/FT_NamingManagerS.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "orbsvcs/FT_NamingManagerC.h" + +#include "orbsvcs/PortableGroup/PG_FactoryRegistry.h" +#include "orbsvcs/PortableGroup/PG_Properties_Support.h" +#include "orbsvcs/Naming/FaultTolerant/FT_PG_Group_Factory.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Round_Robin.h" + +#include "ace/Task.h" +#include "tao/Condition.h" + + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace TAO +{ + class Storable_Factory; +} + +namespace FT_Naming +{ + struct ObjectGroupUpdate; +} + +/** + * @class TAO_FT_Naming_Manager + * @brief Implements the NamingManager interface for the Fault + * tolerant naming service. + * + * This class implements the NamingManager interface in support + * of the load balancing features of the FaultTolerant Naming + * Service. Uses can create and manage object groups which can be + * bound in the Naming Service, which will provide the load balancing + * functionality. + */ +class TAO_FtNaming_Export TAO_FT_Naming_Manager + : public virtual POA_FT_Naming::NamingManager, + public ACE_Task_Base +{ +public: + + /// Constructor. + TAO_FT_Naming_Manager (void); + + /** + * @name FT::NamingManager Methods + * + * + */ + + /// Creates an object group with the specified name and load + /// balancing strategy. + /// @param[in] group_name The symbolic name of the group that can + /// be used to refer to the group in other operations. + /// @param[in] lb_strategy The strategy to be used by the Naming + /// Service when this object group is resolved. + ///@param[in] the_criteria Properties to be used by the object group. + virtual PortableGroup::ObjectGroup_ptr create_object_group ( + const char * group_name, + FT_Naming::LoadBalancingStrategyValue lb_strategy, + const ::PortableGroup::Criteria & the_criteria); + + /// Deletes the object group with the provided group_name. + virtual void delete_object_group ( + const char * group_name); + + /// Retreives a reference to a group with the specified name + virtual PortableGroup::ObjectGroup_ptr get_object_group_ref_from_name ( + const char * group_name); + + /// Provide a new load balancing strategy for the group with the provided + /// name. + virtual void set_load_balancing_strategy ( + const char * group_name, + FT_Naming::LoadBalancingStrategyValue lb_strategy); + + /// Retreive the names of the groups with the specified load balanacing + /// strategy that have been created in this Naming Manager. + virtual FT_Naming::GroupNames * groups ( + ::FT_Naming::LoadBalancingStrategyValue target_strategy); + + /** + * @name PortableGroup::PropertyManager Methods + * + * Methods required by the PortableGroup::PropertyManager interface. + */ + //@{ + + /// Set the default properties to be used by all object groups. + virtual void set_default_properties ( + const PortableGroup::Properties & props); + + /// Get the default properties used by all object groups. + virtual PortableGroup::Properties * get_default_properties (); + + /// Remove default properties. + virtual void remove_default_properties ( + const PortableGroup::Properties & props); + + /// Set properties associated with a given Replica type. These + /// properties override the default properties. + virtual void set_type_properties ( + const char * type_id, + const PortableGroup::Properties & overrides); + + /** + * Return the properties associated with a give Replica type. These + * properties include the type-specific properties in use, in + * addition to the default properties that were not overridden. + */ + virtual PortableGroup::Properties * get_type_properties ( + const char * type_id); + + /// Remove the given properties associated with the Replica type ID. + virtual void remove_type_properties ( + const char * type_id, + const PortableGroup::Properties & props); + + /** + * Dynamically set the properties associated with a given object + * group as the load balancer and replicas are being executed. + * These properties override the type-specific and default + * properties. + */ + virtual void set_properties_dynamically ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Properties & overrides); + + /** + * Return the properties currently in use by the given object + * group. These properties include those that were set dynamically, + * type-specific properties that weren't overridden, properties that + * were used when the Replica was created, and default properties + * that weren't overridden. + */ + virtual PortableGroup::Properties * get_properties ( + PortableGroup::ObjectGroup_ptr object_group); + + //@} + + /** + * @name PortableGroup::ObjectGroupManager methods + * + * Methods required by the PortableGroup::ObjectGroupManager + * interface. + */ + //@{ + + /// Create a member using the load balancer ObjectGroupManager, and + /// add the created object to the ObjectGroup. + virtual PortableGroup::ObjectGroup_ptr create_member ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location, + const char * type_id, + const PortableGroup::Criteria & the_criteria); + + /// Add an existing object to the ObjectGroup. + /// @param[in] object_group A reference for the group to which the + /// specified member is to be added. + /// @param[in] the_location The symbolic value that specifies this + /// specific member. The location can be any string value. + /// @param[in] member The object reference for the member. The first + /// member's type is used to defined the object group type. All subsequence + /// members must have the same type. + virtual PortableGroup::ObjectGroup_ptr add_member ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location, + CORBA::Object_ptr member); + + /** + * Remove an object at a specific location from the given + * ObjectGroup. Deletion of application created objects must be + * deleted by the application. Objects created by the + * infrastructure (load balancer) will be deleted by the + * infrastructure. + */ + virtual PortableGroup::ObjectGroup_ptr remove_member ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & the_location); + + /// Return the locations of the members in the given ObjectGroup. + virtual PortableGroup::Locations * locations_of_members ( + PortableGroup::ObjectGroup_ptr object_group); + + /// Return the locations of the members in the given ObjectGroup. + virtual PortableGroup::ObjectGroups * groups_at_location ( + const PortableGroup::Location & the_location); + + /// Return the ObjectGroupId for the given ObjectGroup. + virtual PortableGroup::ObjectGroupId get_object_group_id ( + PortableGroup::ObjectGroup_ptr object_group); + + /// TAO specific method + virtual PortableGroup::ObjectGroup_ptr get_object_group_ref_from_id ( + PortableGroup::ObjectGroupId group_id); + + /// Return the reference corresponding to the Replica of a given + /// ObjectGroup at the given location. + virtual CORBA::Object_ptr get_member_ref ( + PortableGroup::ObjectGroup_ptr object_group, + const PortableGroup::Location & loc); + + //@} + + /** + * @name PortableGroup::GenericFactory methods + * + * Methods required by the PortableGroup::GenericFactory interface. + */ + //@{ + + /** + * Create an object of the specified type that adheres to the + * restrictions defined by the provided Criteria. The out + * FactoryCreationId parameter may be passed to the delete_object() + * method to delete the object. This signature is modified from + * the generic factory operation to support the use of an object + * name in addition to the factory_creation_id. + */ + virtual CORBA::Object_ptr create_object ( + const char * object_name, + const char * type_id, + const PortableGroup::Criteria & the_criteria, + PortableGroup::GenericFactory::FactoryCreationId_out + factory_creation_id); + + /** + * Delete the object corresponding to the provided + * FactoryCreationId. If the object is actually an ObjectGroup, + * then all members within the ObjectGroup will be deleted. + * Afterward, the ObjectGroup itself will be deleted. + */ + virtual void delete_object ( + const PortableGroup::GenericFactory::FactoryCreationId & + factory_creation_id); + + //@} + + /// Initialize the naming manager. This will provide the poa to + /// the naming manager and underlying components for use in + /// managing the object groups. + void initialize (CORBA::ORB_ptr orb, + PortableServer::POA_ptr root_poa); + + + /// Utilizing the load balancing strategy identified by the object + /// group property, return the next object reference from the object + /// group which should be used to service the next CORBA request + CORBA::Object_ptr next_member (PortableGroup::ObjectGroup_ptr object_group); + + /// Load/save state of object groups from/to file for fault + /// tolerant purposes. + void + set_object_group_storable_factory (TAO::Storable_Factory * + factory); + + /// Indicate the object group state is stale. + /// Only valid when object group persistence is enabled. + void set_object_group_stale (const FT_Naming::ObjectGroupUpdate & group_info); + + /// Destructor. + ~TAO_FT_Naming_Manager (void); + +private: + /// A utility to ensure we can access the latest object reference for + /// the object group when referenced externally. + virtual PortableGroup::ObjectGroup_ptr get_object_group_ref ( + PortableGroup::ObjectGroup_ptr object_group); + + /// TAO specific method /// Preprocess Strategy or CustomStrategy properties. + /** + * This method takes care of converting StrategyInfo properties to + * Strategy properties, and verifying that CustomStrategy references + * are not nil. + */ + void preprocess_properties (PortableGroup::Properties & props); + + /// Utility for accessing the object group name. Returns true if a + /// name is found and allocates a string with the name assigned to + /// the name parameter. + bool group_name (PortableGroup::ObjectGroup_ptr group, char*& name); + + /// Mutex that provides synchronization for the TAO_FT_Naming_Manager's + /// state. + TAO_SYNCH_MUTEX lock_; + + /// an object that manages default and type_id related properties + TAO::PG_Properties_Support properties_support_; + + /// Registry used by the PG_Group_Factory + TAO::PG_FactoryRegistry factory_registry_; + + /// The group factory responsible for creating object groups + TAO::FT_PG_Group_Factory group_factory_; + + /** + * @name Built-in load balancing strategy implementations + * + * "Built-in" load balancing strategies. Currently only RoundRobin + * is supported. + */ + //@{ + + /// The "RoundRobin" load balancing strategy. + TAO_FT_Round_Robin round_robin_; + //@} + + /// Cached instance of the Property name + /// "org.omg.CosLoadBalancing.Strategy". + PortableGroup::Name built_in_balancing_strategy_name_; + + PortableGroup::Name object_group_property_name_; + + TAO_SYNCH_MUTEX validate_lock_; + TAO_Condition<TAO_SYNCH_MUTEX> validate_condition_; + + bool shutdown_; + +}; + + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* TAO_FT_NAMING_MANAGER_H */ diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Replication_Manager.cpp b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Replication_Manager.cpp new file mode 100644 index 00000000000..f86ffb96e0f --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Replication_Manager.cpp @@ -0,0 +1,179 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_Naming_Replication_Manager.cpp + * + * $Id$ + * + * @author Kevin Stanley <stanleyk@ociweb.com> + */ +//============================================================================= + +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Replication_Manager.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Server.h" +#include "tao/corba.h" +#include "ace/SStringfwd.h" + +FT_Naming::ReplicationManager_var +TAO_FT_Naming_Replication_Manager::peer_replica_ (0); + +TAO_FT_Naming_Replication_Manager::TAO_FT_Naming_Replication_Manager ( + TAO_FT_Naming_Server *naming_svr, + const char* repl_mgr_name) + : naming_svr_ (naming_svr), + repl_mgr_name_ (repl_mgr_name) +{ +} + + +TAO_FT_Naming_Replication_Manager::~TAO_FT_Naming_Replication_Manager(void) +{ + this->reference_ = FT_Naming::ReplicationManager::_nil (); +} + +void +TAO_FT_Naming_Replication_Manager::initialize (CORBA::ORB_ptr orb, + PortableServer::POA_ptr repl_mgr_poa) +{ + ACE_UNUSED_ARG (orb); + repl_mgr_poa_ = PortableServer::POA::_duplicate (repl_mgr_poa); + PortableServer::ObjectId_var id = + PortableServer::string_to_ObjectId (this->repl_mgr_name_.c_str ()); + CORBA::Object_var obj = repl_mgr_poa_->id_to_reference (id.in ()); + this->reference_ = FT_Naming::ReplicationManager::_narrow (obj.in ()); +} + +FT_Naming::ReplicaInfo* +TAO_FT_Naming_Replication_Manager::register_replica ( + ::FT_Naming::ReplicationManager_ptr replica, + const ::FT_Naming::ReplicaInfo & replica_info) +{ + ACE_TRACE ( ACE_TEXT("TAO_FT_Naming_Replication_Manager::register_replica")); + + ACE_GUARD_THROW_EX (ACE_SYNCH_MUTEX, + ace_mon, + this->lock_, + CORBA::INTERNAL ()); + + // Store a copy of the provided reference and other ReplicaInfo + peer_replica_ = FT_Naming::ReplicationManager::_duplicate (replica); + + // Store the provided peer references + this->naming_svr_->peer_root_context (replica_info.root_context); + this->naming_svr_->peer_naming_manager (replica_info.naming_manager); + + // Return my references to the peer + FT_Naming::ReplicaInfo* my_info = new FT_Naming::ReplicaInfo; + + my_info->root_context = CosNaming::NamingContext::_duplicate ( + this->naming_svr_->my_root_context ()); + + my_info->naming_manager = FT_Naming::NamingManager::_duplicate ( + this->naming_svr_->my_naming_manager ()); + + return my_info; +} + +void +TAO_FT_Naming_Replication_Manager::notify_updated_object_group ( + const FT_Naming::ObjectGroupUpdate & group_info) +{ + ACE_TRACE ( ACE_TEXT ("TAO_FT_Naming_Replication_Manager::") + ACE_TEXT ("notify_updated_object_group")); + + // Make sure that we have a valid naming server + ACE_ASSERT (naming_svr_); + int result = this->naming_svr_->update_object_group (group_info); + + if (result != 0) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Unable to update object group.\n"))); +} + +void +TAO_FT_Naming_Replication_Manager::notify_updated_context ( + const FT_Naming::NamingContextUpdate & context_info) +{ + ACE_TRACE (ACE_TEXT ("TAO_FT_Naming_Replication_Manager::") + ACE_TEXT ("notify_updated_context")); + ACE_ASSERT (naming_svr_); + int result = this->naming_svr_->update_naming_context (context_info); + + if (result != 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Error while updating naming context.\n"))); + } +} + +FT_Naming::ReplicationManager_ptr +TAO_FT_Naming_Replication_Manager::peer_replica (void) +{ + ACE_TRACE (ACE_TEXT ("TAO_FT_Naming_Replication_Manager::peer_replica")); + // Return a copy of the stored peer to the requester + return FT_Naming::ReplicationManager::_duplicate (peer_replica_.in ()); +} + +int +TAO_FT_Naming_Replication_Manager::register_with_peer_replica ( + FT_Naming::ReplicationManager_ptr replica, + CosNaming::NamingContext_ptr nc, + FT_Naming::NamingManager_ptr nm) +{ + ACE_TRACE (ACE_TEXT ("TAO_FT_Naming_Replication_Manager::") + ACE_TEXT ("register_with_peer_replica")); + + int result = 0; + FT_Naming::ReplicaInfo my_info; + { // Guard the access to the Replication Manager state + ACE_GUARD_THROW_EX (ACE_SYNCH_MUTEX, + ace_mon, + this->lock_, + CORBA::INTERNAL ()); + + // Store a copy of the peer reference for future access + this->peer_replica_ = + FT_Naming::ReplicationManager::_duplicate (replica); + + my_info.root_context = CosNaming::NamingContext::_duplicate (nc); + my_info.naming_manager = FT_Naming::NamingManager::_duplicate (nm); + } + + try { + FT_Naming::ReplicationManager_var my_ref = + this->reference (); + + // Register with the peer replica + FT_Naming::ReplicaInfo_var peer_info = + this->peer_replica_->register_replica (my_ref.in (), + my_info); + + ACE_GUARD_THROW_EX (ACE_SYNCH_MUTEX, + ace_mon, + this->lock_, + CORBA::INTERNAL ()); + + // Store the returned references locally + this->naming_svr_->peer_root_context (peer_info->root_context); + this->naming_svr_->peer_naming_manager (peer_info->naming_manager); + } + catch (const CORBA::Exception& ex) { + // Unable to contact the peer replica. + if (TAO_debug_level > 1) + ex._tao_print_exception ( + ACE_TEXT ("TAO_FT_Naming_Replication_Manager::") + ACE_TEXT ("register_with_peer_replica\n")); + result = -1; + } + + return result; + +} + +FT_Naming::ReplicationManager_ptr +TAO_FT_Naming_Replication_Manager::reference (void) +{ + ACE_TRACE (ACE_TEXT ("TAO_FT_Naming_Replication_Manager::reference")); + return FT_Naming::ReplicationManager::_duplicate (reference_.in ()); +} diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Replication_Manager.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Replication_Manager.h new file mode 100644 index 00000000000..8dc9521576e --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Replication_Manager.h @@ -0,0 +1,110 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_Naming_Replication_Manager.h + * + * $Id$ + * + * @author Kevin Stanley <stanleyk@ociweb.com> + */ +//============================================================================= + + +#ifndef TAO_FT_NAMING_REPLICATION_MANAGER_H +#define TAO_FT_NAMING_REPLICATION_MANAGER_H + +#include /**/ "ace/pre.h" + +#include "orbsvcs/Naming/FaultTolerant/ftnaming_export.h" +#include "orbsvcs/FT_NamingReplicationS.h" +#include "ace/Recursive_Thread_Mutex.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "orbsvcs/FT_NamingReplicationC.h" + +class TAO_FT_Naming_Server; + +/** + * @class TAO_FT_Naming_Replication_Manager + * @brief The class that implements the FT_Naming::ReplicationManager + * interface. + */ +class TAO_FtNaming_Export TAO_FT_Naming_Replication_Manager + : public virtual POA_FT_Naming::ReplicationManager +{ +public: + + /// Create a Replication Manager and provide it with the naming server + /// to be updated whenever notified by the peer replica + TAO_FT_Naming_Replication_Manager(TAO_FT_Naming_Server *naming_svr, + const char* repl_mgr_name); + + virtual ~TAO_FT_Naming_Replication_Manager(void); + + /// Initialize the naming manager. This will provide the poa to + /// the naming manager and underlying components for use in + /// managing the object groups. + void initialize (CORBA::ORB_ptr orb, + PortableServer::POA_ptr root_poa); + + + /// Implementation of the FT_Naming::ReplicationManager interface + virtual ::FT_Naming::ReplicaInfo * register_replica ( + ::FT_Naming::ReplicationManager_ptr replica, + const ::FT_Naming::ReplicaInfo & replica_info); + + /// This method implements the operation invoked by the peer replica when an + /// object group is updated on the remote process. + virtual void notify_updated_object_group ( + const FT_Naming::ObjectGroupUpdate & group_info); + + /// This method implements the operation invoked by the peer replica when an + /// naming context is updated on the remote process. + virtual void notify_updated_context ( + const FT_Naming::NamingContextUpdate & group_info); + + /// Retrieve the object reference for the peer naming service + /// ReplicationManager. + static FT_Naming::ReplicationManager_ptr peer_replica (void); + + /* + * Utilities for implementing the FT_Naming::ReplicationManager + */ + + /// Stores the peer in the peer_replica_ data member and invokes the + /// register_replica interface method with the peer. Returns 0 if + /// successful and -1 if unable to contact the peer. + int register_with_peer_replica (FT_Naming::ReplicationManager_ptr replica, + CosNaming::NamingContext_ptr nc, + FT_Naming::NamingManager_ptr rm); + + /// The object reference for this servant instance + FT_Naming::ReplicationManager_ptr reference (void); + +protected: + + // The object which implements the naming service and the object manager + TAO_FT_Naming_Server *naming_svr_; + + // Store the reference to the replica object reference + // For now only a single replica is supported. + static FT_Naming::ReplicationManager_var peer_replica_; + + PortableServer::POA_var repl_mgr_poa_; + + ACE_CString repl_mgr_name_; + + FT_Naming::ReplicationManager_var reference_; + + /// Lock used to serialize access to fault tolerant extensions + /// to Naming Service. + TAO_SYNCH_MUTEX lock_; + +}; +#include /**/ "ace/post.h" + +#endif /* TAO_FT_NAMING_REPLICATION_MANAGER_H */ diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Server.cpp b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Server.cpp new file mode 100644 index 00000000000..d5eb451e92d --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Server.cpp @@ -0,0 +1,1196 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_Naming_Server.cpp + * + * $Id$ + * + * @author Kevin Stanley <stanleyk@ociweb.com> + */ +//============================================================================= + + +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Server.h" +#include "orbsvcs/Naming/Naming_Server.h" + +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.h" +#include "orbsvcs/Naming/Storable.h" +#include "orbsvcs/Naming/Storable_Naming_Context.h" +#include "orbsvcs/Naming/Storable_Naming_Context_Activator.h" + +#include "orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context_Factory.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context_Factory.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context.h" +#include "orbsvcs/Naming/Persistent_Context_Index.h" +#include "orbsvcs/Naming/Naming_Context_Interface.h" + + +#include "ace/Arg_Shifter.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_unistd.h" + +#include "tao/IORTable/IORTable.h" +#include "tao/ORB_Core.h" + +#include "tao/debug.h" +#include "tao/default_ports.h" +#include "tao/Storable_FlatFileStream.h" + +#include "tao/debug.h" +#include "tao/default_ports.h" + +#include "tao/IORManipulation/IORManip_Loader.h" + +#if defined (TAO_HAS_CORBA_MESSAGING) && TAO_HAS_CORBA_MESSAGING != 0 +#include "tao/Messaging/Messaging.h" +#endif + +#include "tao/AnyTypeCode/Any.h" + +const ACE_TCHAR* +TAO_FT_Naming_Server::primary_replica_ior_filename = + ACE_TEXT ("ns_replica_primary.ior"); + +const ACE_TCHAR* +TAO_FT_Naming_Server::backup_replica_ior_filename = + ACE_TEXT ("ns_replica_backup.ior"); + +/// Default Constructor. +TAO_FT_Naming_Server::TAO_FT_Naming_Server (void) + : replica_id_ (0), + naming_manager_ (), + replication_manager_ (0), + combined_naming_service_ior_file_name_ (0), + combined_naming_manager_ior_file_name_ (0), + naming_manager_ior_file_name_ (0), + naming_manager_persistence_file_name_ (0), + use_object_group_persistence_ (0), + server_role_ (STANDALONE) +{ +} + +int +TAO_FT_Naming_Server::init_with_orb (int argc, + ACE_TCHAR *argv [], + CORBA::ORB_ptr orb) +{ + // Invoke the base class initialization to setup the naming service + // What follows after that are the initialization steps to support + // fault tolerance and load balancing with the FT_Naming_Manager + int result = TAO_Naming_Server::init_with_orb (argc, argv, orb); + + // Check the result to make sure it executed Ok. + if (result != 0) + return result; + + if (this->use_object_group_persistence_) + { + // Make sure the object group directory is accessible + if (ACE_OS::access (this->object_group_dir_.c_str (), W_OK|X_OK)) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Invalid object ") + ACE_TEXT ("group persistence directory\n")), + -1); + } + + TAO::Storable_Factory * object_group_storable_factory; + ACE_NEW_RETURN (object_group_storable_factory, + TAO::Storable_FlatFileFactory (this->object_group_dir_), + -1); + + naming_manager_.set_object_group_storable_factory ( + object_group_storable_factory); + } + + // Provide the naming manager reference for use in + // TAO_FT_Persistent_Naming_Contexts for load balancing functionality + TAO_FT_Storable_Naming_Context::set_naming_manager (&naming_manager_); + + // Initialize the naming manager which supports the Object Group Manager + // interface + result = this->init_naming_manager_with_orb (argc, argv, orb); + if (result != 0) + return result; + + try { + + // Initialize the replication manager + result = init_replication_manager_with_orb (argc, argv, orb); + if (result != 0) + return result; + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("TAO_FT_Naming_Server::init_with_orb")); + return -1; + } + + // If we successfully initialized the replication manager and we are + // a backup server, then we should export the multi-profile + // references to files. + if (this->server_role_ == TAO_FT_Naming_Server::BACKUP) + { + // The backup should write out the combined IOR for the primary + // and backup naming service and naming manager. + result = export_ft_naming_references (); + } + + return result; +} + +int +TAO_FT_Naming_Server::init_naming_manager_with_orb (int argc, + ACE_TCHAR *argv [], + CORBA::ORB_ptr orb) +{ + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + + int result = 0; + + // Need to lock during startup to prevent access of partially + // initialized variables + ACE_GUARD_THROW_EX (ACE_SYNCH_RECURSIVE_MUTEX, + ace_mon, + this->lock_, + CORBA::INTERNAL ()); + + try { + + // Get the POA from the ORB. + CORBA::Object_var poa_object = + orb->resolve_initial_references (ACE_TEXT_ALWAYS_CHAR ("RootPOA")); + + if (CORBA::is_nil (poa_object.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT(" (%P|%t) ERROR: Unable to initialize the POA.\n")), + -1); + } + + if (result != 0) + return result; + + // Get the POA object. + this->root_poa_ = PortableServer::POA::_narrow (poa_object.in ()); + + // Get the POA_Manager. + PortableServer::POAManager_var poa_manager = + this->root_poa_->the_POAManager (); + + int numPolicies = 2; + + CORBA::PolicyList policies (numPolicies); + policies.length (numPolicies); + + // Id Assignment policy + policies[0] = + this->root_poa_->create_id_assignment_policy (PortableServer::USER_ID); + + // Lifespan policy + policies[1] = + this->root_poa_->create_lifespan_policy (PortableServer::PERSISTENT); + + /* Register the naming manager with a POA + * TODO: 1) Error checking + * 2) Write IOR to file + * 3) Persistence for Object Group Manager + */ + + // We use a different POA, otherwise the user would have to change + // the object key each time it invokes the server. + this->naming_manager_poa_ = this->root_poa_->create_POA ( + ACE_TEXT_ALWAYS_CHAR ("NamingManager"), + poa_manager.in (), + policies); + // Warning! If create_POA fails, then the policies won't be + // destroyed and there will be hell to pay in memory leaks! + + // Creation of the new POAs over, so destroy the Policy_ptr's. + for (CORBA::ULong i = 0; + i < policies.length (); + ++i) + { + CORBA::Policy_ptr policy = policies[i]; + policy->destroy (); + } + + poa_manager->activate (); + + // Register with the POA. + PortableServer::ObjectId_var id = + PortableServer::string_to_ObjectId ( + ACE_TEXT_ALWAYS_CHAR ("NamingManager")); + + this->naming_manager_poa_->activate_object_with_id ( + id.in (), + &this->naming_manager_); + + CORBA::Object_var nm_obj = + this->naming_manager_poa_->id_to_reference (id.in ()); + + this->my_naming_manager_ = FT_Naming::NamingManager::_narrow (nm_obj.in ()); + + this->naming_manager_ior_ = + orb->object_to_string (this->my_naming_manager_.in ()); + + // write out our object reference to the file defined in the -h option + if (this->naming_manager_ior_file_name_ != 0) + { + if (this->write_ior_to_file (this->naming_manager_ior_.in (), + this->naming_manager_ior_file_name_) + != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Unable to open %s ") + ACE_TEXT ("for writing:(%u) %p\n"), + this->naming_manager_ior_file_name_, + ACE_ERRNO_GET, + ACE_TEXT ("TAO_Naming_Server::") + ACE_TEXT ("init_naming_manager_with_orb")), + -1); + } + } + + this->naming_manager_.initialize (this->orb_, + this->naming_manager_poa_); + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("TAO_FT_Naming_Server::init_naming_manager_with_orb")); + return -1; + } + + // Make the Object Group Manager easily accessible using Interoperable + // Naming Service IORs + CORBA::Object_var table_object = + orb->resolve_initial_references (ACE_TEXT_ALWAYS_CHAR ("IORTable")); + + IORTable::Table_var adapter = + IORTable::Table::_narrow (table_object.in ()); + if (CORBA::is_nil (adapter.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: TAO_FT_Naming_Server::") + ACE_TEXT ("init_naming_manager_with_orb - Nil IORTable\n"))); + } + else + { + CORBA::String_var ior = this->naming_manager_ior (); + adapter->bind (ACE_TEXT_ALWAYS_CHAR ("NamingManager"), ior.in ()); + } + + return 0; +} + +int +TAO_FT_Naming_Server::init_replication_manager_with_orb (int argc, + ACE_TCHAR *argv [], + CORBA::ORB_ptr orb) +{ + ACE_UNUSED_ARG (argc); + ACE_UNUSED_ARG (argv); + + // Need to lock during startup to prevent access of partially initialized + // variables + ACE_GUARD_THROW_EX (ACE_SYNCH_RECURSIVE_MUTEX, + ace_mon, + this->lock_, + CORBA::INTERNAL ()); + + // If redundancy is not requested, then do not initialize the + // replication manager + if (!this->use_redundancy_) + return 0; + + int result = 0; + + try { + + // Get the POA from the ORB. + CORBA::Object_var poa_object = + orb->resolve_initial_references (ACE_TEXT_ALWAYS_CHAR ("RootPOA")); + + if (CORBA::is_nil (poa_object.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT(" (%P|%t) ERROR: Unable to initialize the POA.\n")), + -1); + } + + if (result != 0) + return result; + + // Get the POA object. + this->root_poa_ = PortableServer::POA::_narrow (poa_object.in ()); + + // Get the POA_Manager. + PortableServer::POAManager_var poa_manager = + this->root_poa_->the_POAManager (); + + int numPolicies = 2; + + CORBA::PolicyList policies (numPolicies); + policies.length (numPolicies); + + // Id Assignment policy + policies[0] = + this->root_poa_->create_id_assignment_policy (PortableServer::USER_ID); + + // Lifespan policy + policies[1] = + this->root_poa_->create_lifespan_policy (PortableServer::PERSISTENT); + + // We use a different POA, otherwise the user would have to change + // the object key each time it invokes the server. + this->replication_manager_poa_ = this->root_poa_->create_POA ( + ACE_TEXT_ALWAYS_CHAR (this->replica_id_ ), + poa_manager.in (), + policies); + + // Warning! If create_POA fails, then the policies won't be + // destroyed and there will be hell to pay in memory leaks! + + // Creation of the new POAs over, so destroy the Policy_ptr's. + for (CORBA::ULong i = 0; + i < policies.length (); + ++i) + { + CORBA::Policy_ptr policy = policies[i]; + policy->destroy (); + } + + poa_manager->activate (); + + // Construct the replication manager providing it with its ID + ACE_NEW_RETURN (this->replication_manager_, + TAO_FT_Naming_Replication_Manager (this, + this->replica_id_), + -1); + + // Register with the POA. + PortableServer::ObjectId_var id = + PortableServer::string_to_ObjectId ( + ACE_TEXT_ALWAYS_CHAR (this->replica_id_)); + + this->replication_manager_poa_->activate_object_with_id ( + id.in (), + this->replication_manager_); + + CORBA::Object_var repl_mgr_ref = + this->replication_manager_poa_->id_to_reference (id.in ()); + + this->replication_manager_ior_ = + orb->object_to_string (repl_mgr_ref.in ()); + + // Provide the replication manager its ORB and POA + this->replication_manager_->initialize ( + this->orb_.in (), + this->replication_manager_poa_.in ()); + + ACE_CString primary_file_name (this->persistence_file_name_); + primary_file_name += ACE_TEXT ("/"); + primary_file_name += + TAO_FT_Naming_Server::primary_replica_ior_filename; + + ACE_CString backup_file_name (this->persistence_file_name_); + backup_file_name += ACE_TEXT ("/"); + backup_file_name += + TAO_FT_Naming_Server::backup_replica_ior_filename; + + if (this->server_role_ == PRIMARY) + { // We are the primary + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server ") + ACE_TEXT ("is a primary\n"))); + + // Write out this replicas IOR for the backup to use to bootstrap + CORBA::String_var replication_ior = naming_service_ior (); + this->write_ior_to_file (this->replication_manager_ior_.in (), + primary_file_name.c_str ()); + + // Check if there is already a backup IOR file. If so, then the backup + // may be up and running so we should register with it. + CORBA::Object_var backup_ior; + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server reading ") + ACE_TEXT ("backup ior file\n"))); + + if ((ACE_OS::access (primary_file_name.c_str (), + R_OK) == 0) && + this->read_reference_from_file (backup_file_name.c_str (), + backup_ior.out ()) == 0) + {// Success in reading backup IOR file + // Store the backup reference as our peer + FT_Naming::ReplicationManager_var peer_ref = + FT_Naming::ReplicationManager::_narrow (backup_ior.in ()); + + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server ") + ACE_TEXT ("narrowing IOR\n"))); + if (CORBA::is_nil (peer_ref.in ())) + ACE_ERROR_RETURN ( + (LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: IOR in file %s is not ") + ACE_TEXT ("a FT_Naming::ReplicationManager\n"), + primary_file_name.c_str ()), + -1); + + try { + if (TAO_debug_level > 3) + ACE_DEBUG ( + (LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server registering ") + ACE_TEXT ("with backup.\n"))); + + // Register with the backup + CosNaming::NamingContext_var root = this->my_root_context (); + FT_Naming::NamingManager_var nm = this->my_naming_manager (); + + int registration_result = + this->replication_manager_->register_with_peer_replica ( + peer_ref.in (), + root.in (), + nm.in ()); + + if (registration_result == 0) + { + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server ") + ACE_TEXT ("registered with backup.\n"))); + } + else + { + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server:Backup peer ") + ACE_TEXT ("replica not started yet.\n"))); + } + } + catch (const CORBA::Exception& ex) + { + // Its Ok that we were unable to contact the backup peer. + // It has apparently not started yet. + // It will register with the primary when it starts up. + ex._tao_print_exception ( + ACE_TEXT ("Backup peer replica not started yet.\n")); + } + } + else + { + // Could not get the backup replica from the IOR file, which is OK. + // The backup will register with us in the future. + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server no Replica ") + ACE_TEXT ("IOR file. Waiting for registration.\n"))); + } + } + else if (this->server_role_ == TAO_FT_Naming_Server::BACKUP) + { // We are the backup + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server:Is a Backup\n"))); + + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server writing ") + ACE_TEXT ("replica ior\n"))); + // Write out the backup ior for use by the primary if it must be restarted. + this->write_ior_to_file (replication_manager_ior_.in (), + backup_file_name.c_str ()); + + // Get the ior file for the primary from the + // persistence directory. If not there, fail. + CORBA::Object_var primary_ref = CORBA::Object::_nil (); + + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server ") + ACE_TEXT ("reading primary ior file\n"))); + // Check for the primary IOR. We must have it to bootstrap the redundant + // naming pair. + if ((ACE_OS::access (primary_file_name.c_str (), R_OK) == 0) && + (this->read_reference_from_file (primary_file_name.c_str (), + primary_ref.out ()) == 0)) + { + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server ") + ACE_TEXT ("toring the primary reference ior\n"))); + // Store the primary reference as our peer + FT_Naming::ReplicationManager_var peer_ref = + FT_Naming::ReplicationManager::_narrow (primary_ref.in ()); + + if (CORBA::is_nil (peer_ref.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: IOR in file %s ") + ACE_TEXT ("is not a FT_Naming::ReplicationManager\n"), + primary_file_name.c_str ()), + -1); + + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server ") + ACE_TEXT ("backup registering with primary.\n"))); + // Register with the primary + CosNaming::NamingContext_var root = this->my_root_context (); + FT_Naming::NamingManager_var nm = this->my_naming_manager (); + int registration_result = + this->replication_manager_->register_with_peer_replica (peer_ref.in (), + root.in (), + nm.in ()); + if (registration_result == -1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Backup unable to ") + ACE_TEXT ("register with the primary\n")), + -1); + } + else + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: No primary IOR ") + ACE_TEXT ("available. Have you started the ") + ACE_TEXT ("primary? Exiting.\n")), + -1); + } + } + else + {// We are neither a primary or replica, but running in standalone mode + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server:Is Standalone\n"))); + + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("TAO_FT_Naming_Server::init_replication_manager_with_orb.\n")); + return -1; + } + + // Success + return 0; +} + + +int +TAO_FT_Naming_Server::parse_args (int argc, + ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("b:c:do:p:s:f:m:z:r:u:v:g:h:")); + + // Define the arguments for primary and backup + get_opts.long_option (ACE_TEXT ("primary"), ACE_Get_Opt::NO_ARG); + get_opts.long_option (ACE_TEXT ("backup"), ACE_Get_Opt::NO_ARG); + bool role_defined = false; + + int c; + int size; +#if !defined (CORBA_E_MICRO) + int result; + + // This is declared this way to avoid warnings from + // some compilers that complain about mismatching types + // in the sscanf. +#if ACE_SIZEOF_VOID_P == ACE_SIZEOF_LONG_LONG + ptrdiff_t address; +#else + long int address; +#endif /* ACE_SIZEOF_VOID_P */ +#endif /* CORBA_E_MICRO */ + + // Make sure only one naming context persistence option is specified + int f_opt_used = 0; + int u_opt_used = 0; + int r_opt_used = 0; + + int v_opt_used = 0; + + // TODO: remove unsupported options with FT Naming Server + while ((c = get_opts ()) != -1) + switch (c) + { + case 'd': // debug flag. + ++TAO_debug_level; + break; + case 'o': // outputs this servers naming service ior to a file. + this->ior_file_name_ = get_opts.opt_arg (); + break; + case 'c': // outputs the multi-profile naming service ior file + this->combined_naming_service_ior_file_name_ = get_opts.opt_arg (); + break; + case 'g': // outputs the mutli-profile object group manager ior file + this->combined_naming_manager_ior_file_name_ = get_opts.opt_arg (); + break; + case 'h': // outputs the object group manager ior to a file + this->naming_manager_ior_file_name_ = get_opts.opt_arg (); + break; + case 'p': + this->pid_file_name_ = get_opts.opt_arg (); + break; + case 's': + size = ACE_OS::atoi (get_opts.opt_arg ()); + if (size >= 0) + this->context_size_ = size; + break; + case 'm': + this->multicast_ = ACE_OS::atoi(get_opts.opt_arg ()); + break; +#if !defined (CORBA_E_MICRO) + case 'b': + result = ::sscanf (ACE_TEXT_ALWAYS_CHAR (get_opts.opt_arg ()), +#if ACE_SIZEOF_VOID_P == ACE_SIZEOF_LONG_LONG + ACE_INT64_FORMAT_SPECIFIER_ASCII, +#else + "%ld", +#endif /* ACE_SIZEOF_VOID_P */ + &address); + if (result == 0 || result == EOF) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Unable to ") + ACE_TEXT ("process <-b> option")), + -1); + this->base_address_ = (void *) address; + break; + case 'f': + this->persistence_file_name_ = get_opts.opt_arg (); + f_opt_used = 1; + break; +#if (TAO_HAS_MINIMUM_POA == 0) && !defined (CORBA_E_COMPACT) + case 'r': + this->use_redundancy_ = 1; + this->use_storable_context_ = 1; + this->persistence_file_name_ = get_opts.opt_arg (); + r_opt_used = 1; + break; + case 'u': + this->use_storable_context_ = 1; + this->persistence_file_name_ = get_opts.opt_arg (); + u_opt_used = 1; + break; + case 'v': + this->use_object_group_persistence_ = 1; + this->object_group_dir_ = get_opts.opt_arg (); + v_opt_used = 1; + break; + +#endif /* TAO_HAS_MINIMUM_POA == 0 */ +#endif /* !CORBA_E_MICRO */ + case 'z': + this->use_round_trip_timeout_ = 1; + this->round_trip_timeout_ = + (int)1.0e7 * ACE_OS::atoi (get_opts.opt_arg ()); + break; + case 0: // A long option was found + { + const char* long_option = get_opts.long_option (); + if (ACE_OS::strcmp (long_option, ACE_TEXT ("backup")) == 0) + { + this->replica_id_ = ACE_TEXT ("Backup"); + this->server_role_ = TAO_FT_Naming_Server::BACKUP; + role_defined = true; + } + else if (ACE_OS::strcmp (long_option, + ACE_TEXT ("primary")) == 0) + { + this->replica_id_ = ACE_TEXT ("Primary"); + this->server_role_ = TAO_FT_Naming_Server::PRIMARY; + role_defined = true; + } + } + break; + case '?': + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("usage: %s\n") + ACE_TEXT ("--primary (not used with --backup)\n") + ACE_TEXT ("--backup (not used with --primary)\n") + ACE_TEXT ("-d\n") + ACE_TEXT ("-c <multi-profile_name_service_ior_file>\n") + ACE_TEXT ("-o <name_svc_ior_output_file>\n") + ACE_TEXT ("-g <multi-profile_naming_mgr_ior_file>\n") + ACE_TEXT ("-h <naming_mgr_ior_output_file>\n") + ACE_TEXT ("-p <pid_file_name>\n") + ACE_TEXT ("-s <context_size>\n") + ACE_TEXT ("-b <base_address>\n") + ACE_TEXT ("-m <1=enable multicast,") + ACE_TEXT (" 0=disable multicast(default)>\n") + ACE_TEXT ("-n <num_threads>\n") + ACE_TEXT ("-f <persistence_file_name>\n") + ACE_TEXT ("-u <storable_persistence_directory") + ACE_TEXT (" (not used with -f)>\n") + ACE_TEXT ("-v <storable_object_group_persistence") + ACE_TEXT ("_directory>\n") + ACE_TEXT ("-r <redundant_persistence_directory>\n") + ACE_TEXT ("-z <relative round trip timeout>\n") + ACE_TEXT ("\n"), + argv [0]), + -1); + } + + + if (f_opt_used + u_opt_used + r_opt_used > 1) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Only one persistence option ") + ACE_TEXT ("can be provided.\n\n")), + -1); + + // If naming context or object group persistence is being used then + // enable backup/restore compability of persitent files. + if (u_opt_used || r_opt_used || v_opt_used) + { + TAO::Storable_Base::use_backup_default = true; + } + + if (!role_defined) + { // No role specified, so we will become a STANDALONE server + this->replica_id_ = ACE_TEXT ("Standalone"); + this->server_role_ = TAO_FT_Naming_Server::STANDALONE; + // User has not provided a role, so we will not use redundancy option + if (this->use_redundancy_ == 1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("INFO: Cannot run standalone with ") + ACE_TEXT ("-r option. Using -u instead.\n") + ACE_TEXT ("Must start a '--primary' and a '--backup' ") + ACE_TEXT ("server to run as a Fault \n") + ACE_TEXT ("Tolerant Naming Service. \n"))); + this->use_redundancy_ = 0; + } + + } + else + { + // Only the backup should be requested to write the multi-profile IOR + if ((this->server_role_ != TAO_FT_Naming_Server::BACKUP) && + (this->combined_naming_service_ior_file_name_ != 0)) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Must export the multi-profile ") + ACE_TEXT ("IOR (using '-c' option) from the backup") + ACE_TEXT (" server.\n\n")), + -1); + + // Only the backup should be requested to write the multi-profile IOR + if ((this->server_role_ == TAO_FT_Naming_Server::BACKUP) && + (this->combined_naming_service_ior_file_name_ == 0)) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Must export the multi-profile ") + ACE_TEXT ("IOR (using '-c' option) from the backup") + ACE_TEXT (" server.\n\n")), + -1); + + } + return 0; +} + +int +TAO_FT_Naming_Server::fini (void) +{ + // Destroy the child POAs created when initializing + // the FT Naming Service + try + { + if (!CORBA::is_nil (this->naming_manager_poa_.in ())) + this->naming_manager_poa_->destroy (1, 1); + this->naming_manager_poa_ = PortableServer::POA::_nil (); + + if (!CORBA::is_nil (this->replication_manager_poa_.in ())) + this->replication_manager_poa_->destroy (1, 1); + + this->replication_manager_poa_ = PortableServer::POA::_nil (); + CORBA::Object_var table_object = + this->orb_->resolve_initial_references ( + ACE_TEXT_ALWAYS_CHAR ("IORTable")); + + IORTable::Table_var adapter = + IORTable::Table::_narrow (table_object.in ()); + if (CORBA::is_nil (adapter.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Nil IORTable\n"))); + } + else + { + adapter->unbind (ACE_TEXT_ALWAYS_CHAR ("NameService")); + adapter->unbind (ACE_TEXT_ALWAYS_CHAR ("NamingManager")); + } + +#if !defined (CORBA_E_MICRO) + CORBA::Object_var svc = + this->orb_->unregister_initial_reference ( + ACE_TEXT_ALWAYS_CHAR ("NameService")); + this->orb_->unregister_initial_reference ( + ACE_TEXT_ALWAYS_CHAR ("NamingManager")); +#endif /* CORBA_E_MICRO */ + + } + catch (const CORBA::Exception&) + { + // Ignore + } + + // Specific FT_Naming cleanup + naming_manager_poa_ = PortableServer::POA::_nil (); + replication_manager_poa_ = PortableServer::POA::_nil (); + my_naming_manager_ = FT_Naming::NamingManager::_nil (); + peer_naming_manager_ = FT_Naming::NamingManager::_nil (); + peer_root_context_ = CosNaming::NamingContext::_nil (); + +#if !defined (CORBA_E_MICRO) + delete this->context_index_; + delete replication_manager_; +#endif /* CORBA_E_MICRO */ + + // Invoke the base class fini + return TAO_Naming_Server::fini (); +} + +TAO_Storable_Naming_Context_Factory * +TAO_FT_Naming_Server::storable_naming_context_factory (size_t context_size) +{ + return new (ACE_nothrow) TAO_FT_Storable_Naming_Context_Factory (context_size); +} + +TAO_Persistent_Naming_Context_Factory * +TAO_FT_Naming_Server::persistent_naming_context_factory (void) +{ + return new (ACE_nothrow) TAO_FT_Persistent_Naming_Context_Factory; +} + + +int +TAO_FT_Naming_Server::read_reference_from_file (const char* replica_file_name, + CORBA::Object_out obj_ref) +{ + + ACE_CString replica_ior_string ("file://"); + replica_ior_string += replica_file_name; + + try { + CORBA::Object_var object = + this->orb_->string_to_object (replica_ior_string.c_str ()); + if (CORBA::is_nil (object.in ())) + { + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) - invalid ior in file <%s>\n"), + replica_file_name)); + + return -1; + } + + obj_ref = object._retn (); + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Invalid object reference in file: %s\n")); + return -1; + } + + return 0; +} + +int +TAO_FT_Naming_Server::export_ft_naming_references (void) +{ + int result = 0; + + switch (this->server_role_) { + // Neither the PRIMARY or STANDALONE server roles are able to write + // a multi-profile IOR for the redundant server pair. + case TAO_FT_Naming_Server::STANDALONE: + case TAO_FT_Naming_Server::PRIMARY: + + if (this->naming_manager_ior_file_name_ != 0) + { + FT_Naming::NamingManager_var my_nm = + this->my_naming_manager (); + CORBA::String_var naming_manager_ior_string = + this->orb_->object_to_string (my_nm.in ()); + this->write_ior_to_file (naming_manager_ior_string.in (), + this->naming_manager_ior_file_name_); + } + + // Make sure the user provided an ior_file_name for the comb + if (this->combined_naming_service_ior_file_name_ != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Unable to write combined") + ACE_TEXT (" NameService IOR file. ") + ACE_TEXT ("Only supported by the backup naming service.\n") + ACE_TEXT ("Provide the -c option to the --backup role.\n")), + -1); + } + return 0; + break; + + case TAO_FT_Naming_Server::BACKUP: + { + // Make sure the user provided an ior_file_name for the multi-profile ior file + if (this->combined_naming_service_ior_file_name_ == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Unable to write combined") + ACE_TEXT (" NameService IOR file. ") + ACE_TEXT ("No file name provided.\n")), + -1); + return 0; + } + + CORBA::Object_var peer_root_cxt = this->peer_root_context (); + if (CORBA::is_nil (peer_root_cxt.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Unable to get the primary") + ACE_TEXT (" NameService object ref")), + -1); + } + + CORBA::Object_var my_root_cxt = this->my_root_context (); + if (CORBA::is_nil (my_root_cxt.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Unable to get this") + ACE_TEXT (" services NameService object ref")), + -1); + } + + CORBA::Object_ptr IORM = + this->orb_->resolve_initial_references (TAO_OBJID_IORMANIPULATION, 0); + + TAO_IOP::TAO_IOR_Manipulation_var iorm = + TAO_IOP::TAO_IOR_Manipulation::_narrow (IORM); + + // Combine the primary and backup (my) object references for the naming service + CORBA::Object_var combined_obj_ref = + iorm->add_profiles (peer_root_cxt.in (), + my_root_cxt.in ()); + + if (CORBA::is_nil (combined_obj_ref.in ())) + { + ACE_ERROR((LM_ERROR, + ACE_TEXT("(%P|%t) ERROR: could not combine") + ACE_TEXT(" primary and backup IORs for") + ACE_TEXT(" fault tolerant Naming Service.\n"))); + return -1; + } + + CORBA::String_var combined_nameservice_ior_string = + this->orb_->object_to_string (combined_obj_ref.in ()); + + // Write out the combined IOR for the NameService + this->write_ior_to_file (combined_nameservice_ior_string.in (), + this->combined_naming_service_ior_file_name_); + + // Verify that a naming manager ior file name was provided by user + if (this->combined_naming_manager_ior_file_name_ == 0) + { + if (TAO_debug_level > 3) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - FT_Naming_Server:No NamingManager") + ACE_TEXT (" IOR file name provided") + ACE_TEXT (" with -g option. Not writing IOR.\n"))); + } + else + {// A file name was provided to store the naming manager IOR + + FT_Naming::NamingManager_var peer_nm = + this->peer_naming_manager (); + FT_Naming::NamingManager_var my_nm = + this->my_naming_manager (); + + // This is the object reference for the fault tolerant + // naming manager. The primary should be first. + combined_obj_ref = + iorm->add_profiles (peer_nm.in (), + my_nm.in ()); + + if (CORBA::is_nil (combined_obj_ref.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("(%P|%t) ERROR: could not combine") + ACE_TEXT(" primary and backup IORs for") + ACE_TEXT(" fault tolerant Naming Manager.\n")), + -1); + } + + CORBA::String_var combined_naming_manager_ior_string = + this->orb_->object_to_string (combined_obj_ref.in ()); + + // Write out the combined IOR for the NameService + this->write_ior_to_file (combined_naming_manager_ior_string.in (), + this->combined_naming_manager_ior_file_name_); + } + + return 0; + } + break; + }; + return result; +} + + + +/// Return the IOR for the registered replication manager +char* +TAO_FT_Naming_Server::replication_manager_ior (void) +{ + return CORBA::string_dup (this->replication_manager_ior_.in ()); +} + + +/// Return the IOR for the registered object group manager +char* +TAO_FT_Naming_Server::naming_manager_ior (void) +{ + return CORBA::string_dup (this->naming_manager_ior_.in ()); +} + +int +TAO_FT_Naming_Server::update_object_group ( + const FT_Naming::ObjectGroupUpdate & group_info) +{ + ACE_GUARD_THROW_EX (ACE_SYNCH_RECURSIVE_MUTEX, + ace_mon, + this->lock_, + CORBA::INTERNAL ()); + + if (this->use_object_group_persistence_) + { + if (TAO_debug_level > 3) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("%T %n (%P|%t) - ") + ACE_TEXT ("An update of object group with ID %lld ") + ACE_TEXT ("has been made by the peer"), + group_info.id + )); + } + this->naming_manager_.set_object_group_stale (group_info); + } + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Attempting to update object group ") + ACE_TEXT ("as stale with obect group persistence not ") + ACE_TEXT ("enabled."))); + return -1; + } + + return 0; +} + +int +TAO_FT_Naming_Server::update_naming_context ( + const FT_Naming::NamingContextUpdate & context_info) +{ + ACE_GUARD_THROW_EX (ACE_SYNCH_RECURSIVE_MUTEX, + ace_mon, + this->lock_, + CORBA::INTERNAL ()); + + PortableServer::ServantBase_var servant; + + // Lookup the servant for the identified context and see if it is + // active here locally. + try { + // Get the servant if it exists in this process + PortableServer::ObjectId_var context_id = + PortableServer::string_to_ObjectId (context_info.context_name); + servant = this->ns_poa_->id_to_servant (context_id); + } + catch (PortableServer::POA::ObjectNotActive&) + { // No servant registered for this object reference so no need to create it. + // It will be created on first access in incarnate function + + // This context is not currently active in this server so + // there is nothing to be done, so return success. + return 0; + } + + TAO_Naming_Context* changed_context_servant = + dynamic_cast<TAO_Naming_Context*> (servant.in ()); + + if (changed_context_servant == 0) + { // Another type of class was used as the servant. Should not happen. + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Invalid servant type registered") + ACE_TEXT (" with oid: %s"), + context_info.context_name.in ())); + return -1; + } + + if (TAO_debug_level > 3) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("%T %n (%P|%t) - ") + ACE_TEXT ("An update of naming context with name %s ") + ACE_TEXT ("has been made by the peer"), + context_info.context_name.in () + )); + } + + // Mark the local context stale, so we will reload it next + // time it is modified or accessed. + changed_context_servant->stale (true); + + return 0; +} + +/// Destructor. +TAO_FT_Naming_Server::~TAO_FT_Naming_Server (void) +{ + // Clear out the static naming manager from the persistent naming context + TAO_FT_Persistent_Naming_Context::set_naming_manager_impl (0); +} + + +void +TAO_FT_Naming_Server::peer_root_context (CosNaming::NamingContext_ptr peer_cxt) +{ + peer_root_context_ = CosNaming::NamingContext::_duplicate (peer_cxt); +} + +CosNaming::NamingContext_ptr +TAO_FT_Naming_Server::peer_root_context (void) +{ + return CosNaming::NamingContext::_duplicate (peer_root_context_.in ()); +} + +CosNaming::NamingContext_ptr +TAO_FT_Naming_Server::my_root_context (void) const +{ + return CosNaming::NamingContext::_duplicate (this->naming_context_.in ()); +} + +void +TAO_FT_Naming_Server::peer_naming_manager (FT_Naming::NamingManager_ptr peer_cxt) +{ + peer_naming_manager_ = FT_Naming::NamingManager::_duplicate (peer_cxt); +} + +FT_Naming::NamingManager_ptr +TAO_FT_Naming_Server::peer_naming_manager (void) +{ + return FT_Naming::NamingManager::_duplicate (peer_naming_manager_.in ()); +} + +FT_Naming::NamingManager_ptr +TAO_FT_Naming_Server::my_naming_manager (void) const +{ + return FT_Naming::NamingManager::_duplicate (this->my_naming_manager_.in ()); +} diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Server.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Server.h new file mode 100644 index 00000000000..053db29c525 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Naming_Server.h @@ -0,0 +1,189 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_Naming_Server.h + * + * $Id$ + * + * Implement functionality necessary for fault tolerant naming service. + * Adds support for Object Group Manager interfaces as well. This class + * extends the TAO_Naming_Server. + * + * @author Kevin Stanley + */ +//============================================================================= +// + +#ifndef TAO_FT_NAMING_SERVER_H +#define TAO_FT_NAMING_SERVER_H + +#include "orbsvcs/Naming/Naming_Server.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Replication_Manager.h" +#include "orbsvcs/Naming/FaultTolerant/ftnaming_export.h" +#include "tao/IORManipulation/IORManip_Loader.h" +#include "ace/Recursive_Thread_Mutex.h" + +/** + * @class TAO_FT_Naming_Server + * + * @brief Defines a class derived from the TAO_Naming_Server to extend + the functionality to support an ObjectGroupManager interface and a + load balancing capability for objects that are bound within an object + group within the naming service. The Naming Service will extend the + resolve and resolve_str operations to perform load balancing on the + objects within the object group using a specified load balancing + strategy. + */ +class TAO_FtNaming_Export TAO_FT_Naming_Server : public TAO_Naming_Server +{ +public: + /// Default Constructor. + TAO_FT_Naming_Server (void); + + /// Initialize the Naming Service and Object Group Manager with the command line + /// arguments and the ORB. Overrridden from TAO_Naming_Server + virtual int init_with_orb (int argc, ACE_TCHAR *argv [], CORBA::ORB_ptr orb); + + /** + * Accessors and mutators for object references. + */ + /// Returns a <NamingContext_ptr> for the root Naming Context. + CosNaming::NamingContext_ptr my_root_context (void) const; + + /// Returns the reference for this servers local naming manager servant. + FT_Naming::NamingManager_ptr my_naming_manager (void) const; + + void peer_root_context (CosNaming::NamingContext_ptr peer_cxt); + CosNaming::NamingContext_ptr peer_root_context (void); + + void peer_naming_manager (FT_Naming::NamingManager_ptr peer_nm); + FT_Naming::NamingManager_ptr peer_naming_manager (void); + + /// Initialize the naming manager with the ORB. + int init_naming_manager_with_orb (int argc, + ACE_TCHAR *argv [], + CORBA::ORB_ptr orb); + + /// Initialize the replication manager with the ORB. + int init_replication_manager_with_orb (int argc, + ACE_TCHAR *argv [], + CORBA::ORB_ptr orb); + + /// Overridden parse operation. Only allows options supported by the FT_Naming_Server + /// and adds options for the object group manager + virtual int parse_args (int argc, + ACE_TCHAR *argv[]); + + /// Factory method to create a naming context factory for use with + /// the -u and -r options. + virtual TAO_Storable_Naming_Context_Factory * + storable_naming_context_factory (size_t context_size); + + /// Factory method to create a naming context factory for use with + /// the -f option. + virtual TAO_Persistent_Naming_Context_Factory * + persistent_naming_context_factory (void); + + /// Returns the IOR of the replication manager. + char* replication_manager_ior (void); + + /// Returns the IOR of the naming manager. + char * naming_manager_ior (void); + + virtual int update_object_group ( + const FT_Naming::ObjectGroupUpdate & group_info); + + virtual int update_naming_context ( + const FT_Naming::NamingContextUpdate & naming_context); + + /// Destroy the child POAs created in @c init_with_orb, + /// @c init_naming_manager_with_orb, and + /// @c init_replication_manager_with_orb + virtual int fini (void); + + /// Destructor. + virtual ~TAO_FT_Naming_Server (void); + +protected: + + /// Read the replica from the specified file + int read_reference_from_file (const char* replica_file_name, + CORBA::Object_out obj_ref); + + /// Export the NameService and NameManager combined object references + /// to the file names provided + int export_ft_naming_references (void); + + const ACE_TCHAR * replica_id_; + + /// The object that implements the ObjectGroupManager, PropertyManager, + /// and GenericFactory interfaces. + TAO_FT_Naming_Manager naming_manager_; + + /// Object reference for the local naming manager servant. + FT_Naming::NamingManager_var my_naming_manager_; + + /// Object reference for the peer naming service's naming manager. + FT_Naming::NamingManager_var peer_naming_manager_; + + /// Object reference for the peer naming service's naming manager. + CosNaming::NamingContext_var peer_root_context_; + + /// The object that implements the FT_Naming::Replication_Manager + /// interface. + TAO_FT_Naming_Replication_Manager* replication_manager_; + + /// File to output for the multi-profile root naming context IOR. + const ACE_TCHAR *combined_naming_service_ior_file_name_; + + /// File to output the multi-profile object group manager IOR. + const ACE_TCHAR *combined_naming_manager_ior_file_name_; + + /// File to output the object group manager IOR. + const ACE_TCHAR *naming_manager_ior_file_name_; + + /// Path to the file to be used to store/read in Object Group Manager + /// persistent state. + const ACE_TCHAR *naming_manager_persistence_file_name_; + + /// The IOR string of the object group manager. + CORBA::String_var naming_manager_ior_; + + /// The IOR string of the object group manager. + CORBA::String_var replication_manager_ior_; + + /// The IOR string of the peer replica. + CORBA::String_var replica_peer_ior_; + + /// The Object Group Manager POA. + PortableServer::POA_var naming_manager_poa_; + + /// The POA used for replication coordination between + /// primary and backup. + PortableServer::POA_var replication_manager_poa_; + + int use_object_group_persistence_; + ACE_CString object_group_dir_; + + /// The role this server is supporting in the dual redundant + /// replication scheme. + enum ServerRole { PRIMARY, BACKUP, STANDALONE }; + + /// The role this server is to take on. Controlled by the + /// --primary or --backup command line arguments. Defaults + /// to STANDALONE if no role is provided in command line. + ServerRole server_role_; + + /// Lock used to serialize access to fault tolerant extensions + /// to Naming Service. + TAO_SYNCH_RECURSIVE_MUTEX lock_; + +private: + static const ACE_TCHAR* primary_replica_ior_filename; + static const ACE_TCHAR* backup_replica_ior_filename; + + }; + +#endif /* TAO_FT_NAMING_SERVER_H */ diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_PG_Group_Factory.cpp b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_PG_Group_Factory.cpp new file mode 100644 index 00000000000..07e2e52a3f8 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_PG_Group_Factory.cpp @@ -0,0 +1,132 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_PG_Group_Factory.cpp + * + * $Id$ + * + * @author Byron Harris <harrisb@ociweb.com> + */ +//============================================================================= + +#include "orbsvcs/Naming/FaultTolerant/FT_PG_Group_Factory.h" +#include "orbsvcs/Naming/FaultTolerant/FT_PG_Object_Group_Storable.h" + +#include "orbsvcs/PortableGroup/PG_Group_List_Store.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +TAO::FT_PG_Group_Factory::FT_PG_Group_Factory() +{ +} + +TAO::FT_PG_Group_Factory::~FT_PG_Group_Factory() +{ +} + +void +TAO::FT_PG_Group_Factory::set_object_group_stale ( + const FT_Naming::ObjectGroupUpdate & group_info) +{ + if (this->use_persistence_) + { + PortableGroup::ObjectGroupId group_id = group_info.id; + + // If a group was added or destroyed then the group list could be stale. + if (group_info.change_type == FT_Naming::NEW || + group_info.change_type == FT_Naming::DELETED) + { + if (TAO_debug_level > 3) + { + ACE_CString change_type_str (ACE_TEXT ("created")); + if (group_info.change_type == FT_Naming::DELETED) + change_type_str = ACE_TEXT ("deleted"); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("%T %n (%P|%t) - ") + ACE_TEXT ("Setting list store as stale "), + ACE_TEXT ("because of group with ID %lld "), + ACE_TEXT ("was %s"), + group_id, change_type_str.c_str () + )); + } + this->list_store_->stale(true); + } + + PG_Object_Group * group = 0; + if (!find_group (group_id, group)) + { + throw PortableGroup::ObjectNotFound (); + } + FT_PG_Object_Group_Storable * og = + dynamic_cast<FT_PG_Object_Group_Storable *> (group); + + if (TAO_debug_level > 3) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("%T %n (%P|%t) - ") + ACE_TEXT ("Setting object group with ID %lld as stale"), + group_id + )); + } + og->stale (true); + } + else + { + throw CORBA::INTERNAL (); + } +} + +TAO::PG_Object_Group_Storable * +TAO::FT_PG_Group_Factory::create_persistent_group ( + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + CORBA::Object_ptr empty_group, + const PortableGroup::TagGroupTaggedComponent & tagged_component, + const char * type_id, + const PortableGroup::Criteria & the_criteria, + TAO::PG_Property_Set * type_properties, + TAO::Storable_Factory & storable_factory) +{ + TAO::PG_Object_Group_Storable * objectGroup = 0; + ACE_NEW_THROW_EX ( + objectGroup, + TAO::FT_PG_Object_Group_Storable ( + orb, + factory_registry, + manipulator, + empty_group, + tagged_component, + type_id, + the_criteria, + type_properties, + storable_factory + ), + CORBA::NO_MEMORY()); + return objectGroup; +} + +TAO::PG_Object_Group_Storable * +TAO::FT_PG_Group_Factory::restore_persistent_group ( + PortableGroup::ObjectGroupId group_id, + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + TAO::Storable_Factory & storable_factory) +{ + TAO::PG_Object_Group_Storable * objectGroup = 0; + ACE_NEW_THROW_EX ( + objectGroup, + TAO::FT_PG_Object_Group_Storable ( + group_id, + orb, + factory_registry, + manipulator, + storable_factory + ), + CORBA::NO_MEMORY()); + return objectGroup; +} + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_PG_Group_Factory.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_PG_Group_Factory.h new file mode 100644 index 00000000000..22d0b0c88b9 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_PG_Group_Factory.h @@ -0,0 +1,82 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_PG_Group_Factory.h + * + * $Id$ + * + * @author Byron Harris <harrisb@ociweb.com> + */ +//============================================================================= + +#ifndef FT_TAO_PG_GROUP_FACTORY_H +#define FT_TAO_PG_GROUP_FACTORY_H + +#include /**/ "ace/pre.h" + +#include "orbsvcs/Naming/FaultTolerant/ftnaming_export.h" + +#include "orbsvcs/PortableGroup/PG_Group_Factory.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace FT_Naming +{ + struct ObjectGroupUpdate; +} + +namespace TAO +{ + + /** + * class FT_PG_Group_Factory + */ + class TAO_FtNaming_Export FT_PG_Group_Factory : public PG_Group_Factory + { + public: + + /// Constructor. + FT_PG_Group_Factory (); + + /// Destructor. + ~FT_PG_Group_Factory (); + + /** + * indicate the object group state is stale. + * only valid when object group persistence is enabled. + */ + void set_object_group_stale (const FT_Naming::ObjectGroupUpdate & group_info); + + protected: + + virtual PG_Object_Group_Storable * create_persistent_group ( + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + CORBA::Object_ptr empty_group, + const PortableGroup::TagGroupTaggedComponent & tagged_component, + const char * type_id, + const PortableGroup::Criteria & the_criteria, + TAO::PG_Property_Set * type_properties, + TAO::Storable_Factory & storable_factory); + + virtual PG_Object_Group_Storable * restore_persistent_group ( + PortableGroup::ObjectGroupId group_id, + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + TAO::Storable_Factory & storable_factory); + + }; +} // namespace TAO + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* FT_TAO_PG_GROUP_FACTORY_H */ diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_PG_Object_Group_Storable.cpp b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_PG_Object_Group_Storable.cpp new file mode 100644 index 00000000000..4617755347d --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_PG_Object_Group_Storable.cpp @@ -0,0 +1,182 @@ +// $Id$ + +#include "orbsvcs/Naming/FaultTolerant/FT_PG_Object_Group_Storable.h" +#include "orbsvcs/PortableGroup/PG_Object_Group_Storable.h" + +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Replication_Manager.h" +#include "tao/Stub.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +TAO::FT_PG_Object_Group_Storable::FT_PG_Object_Group_Storable ( + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + CORBA::Object_ptr empty_group, + const PortableGroup::TagGroupTaggedComponent & tagged_component, + const char * type_id, + const PortableGroup::Criteria & the_criteria, + TAO::PG_Property_Set * type_properties, + TAO::Storable_Factory & storable_factory) + : PG_Object_Group_Storable(orb, + factory_registry, + manipulator, + empty_group, + tagged_component, + type_id, + the_criteria, + type_properties, + storable_factory) + , stale_ (false) + , file_created_ (false) +{ +} + +TAO::FT_PG_Object_Group_Storable::FT_PG_Object_Group_Storable ( + PortableGroup::ObjectGroupId group_id, + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + TAO::Storable_Factory & storable_factory) + : PG_Object_Group_Storable(group_id, + orb, + factory_registry, + manipulator, + storable_factory) + , stale_ (false) + , file_created_ (true) +{ +} + +TAO::FT_PG_Object_Group_Storable::~FT_PG_Object_Group_Storable (void) +{ +} + +void +TAO::FT_PG_Object_Group_Storable::stale (bool is_stale) +{ + this->stale_ = is_stale; +} + +bool +TAO::FT_PG_Object_Group_Storable::stale () +{ + return this->stale_; +} + +int +TAO::FT_PG_Object_Group_Storable::propagate_update_notification + (FT_Naming::ChangeType change_type) +{ + // Notify the peer of the changed context + FT_Naming::ReplicationManager_var peer = + TAO_FT_Naming_Replication_Manager::peer_replica (); + + if (CORBA::is_nil (peer.in ())) + { + // Replication is not supported without a peer replica. + return 1; + } + + FT_Naming::ObjectGroupUpdate object_group_info; + object_group_info.id = PG_Object_Group::get_object_group_id (); + object_group_info.change_type = change_type; + + try { + // Notify the naming_manager of the updated context + if (TAO_debug_level > 3) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("%T %n (%P|%t) - ") + ACE_TEXT ("Notifying peer that object group with ID %lld ") + ACE_TEXT ("has been updated"), object_group_info.id + )); + } + peer->notify_updated_object_group (object_group_info); + } + catch (CORBA::Exception& ex) + { + if (TAO_debug_level > 3) + ex._tao_print_exception ( + ACE_TEXT ("Unable to communicate with peer.\n")); + return -1; + } + + return 0; +} + +void +TAO::FT_PG_Object_Group_Storable::state_written (void) +{ + FT_Naming::ChangeType change_type; + + if (!this->file_created_) + { + change_type = FT_Naming::NEW; + this->file_created_ = true; + } + else if (this->destroyed_) + change_type = FT_Naming::DELETED; + else + change_type = FT_Naming::UPDATED; + + // If peer is available notify that state has changed. + // Otherwise, rely on file time stamps exclusively + // for update notification. + this->propagate_update_notification (change_type); + + this->write_occurred_ = false; +} + +bool +TAO::FT_PG_Object_Group_Storable::is_obsolete (time_t stored_time) +{ + ACE_UNUSED_ARG (stored_time); + return (!this->loaded_from_stream_) || this->stale_; +} + +PortableGroup::ObjectGroup_ptr +TAO::FT_PG_Object_Group_Storable::add_member_to_iogr (CORBA::Object_ptr member) +{ + // If this is the first member added to the group and it's type_id does + // not match the member, then the object group should assume the same + // type id as the first member. We will need to replace the object + // reference with an empty reference of the specified type id. + + if (CORBA::is_nil (member)) + {// A null object reference is not an acceptable member of the group. + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Unable to add null member ") + ACE_TEXT ("to object group with id: %s\n"), + this->tagged_component_.object_group_id)); + return CORBA::Object::_nil (); + } + + const char* member_type_id = member->_stubobj ()->type_id.in (); + + if ((this->members_.current_size () == 0) && + (ACE_OS::strcmp (this->type_id_, member_type_id) != 0) ) + { + try { + this->type_id_ = member_type_id; + this->reference_ = manipulator_.create_object_group_using_id ( + this->type_id_, + this->tagged_component_.group_domain_id, + this->tagged_component_.object_group_id); + } + catch (const CORBA::Exception&) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) ERROR: Unable to add member ") + ACE_TEXT ("to object group with id: %s for object ") + ACE_TEXT ("of type: %s\n"), + this->tagged_component_.object_group_id, + member_type_id)); + return CORBA::Object::_nil (); + } + } + + return PG_Object_Group::add_member_to_iogr (member); +} + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_PG_Object_Group_Storable.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_PG_Object_Group_Storable.h new file mode 100644 index 00000000000..374400188f0 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_PG_Object_Group_Storable.h @@ -0,0 +1,132 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_PG_Object_Group_Storable.h + * + * $Id$ + * + * Contains declaration for class FT_PG_Object_Group_Storable. + * + * @author Byron Harris <harrisb@ociweb.com> + */ +//============================================================================= + +#ifndef FT_TAO_PG_OBJECT_GROUP_STORABLE_H_ +#define FT_TAO_PG_OBJECT_GROUP_STORABLE_H_ +#include /**/ "ace/pre.h" + +#include "orbsvcs/Naming/FaultTolerant/ftnaming_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + + +///////////////////////////////// +// Includes needed by this header +#include "orbsvcs/PortableGroup/PG_Object_Group_Storable.h" +#include "orbsvcs/FT_NamingReplicationC.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +//////////////// +// Class declarations +namespace TAO +{ + /** + * An object group whose state persists to a stream so that its state + * can be saved/retrieved between processes that use the group. + */ + class TAO_FtNaming_Export FT_PG_Object_Group_Storable + : public PG_Object_Group_Storable + { + + ///////////////////// + // Construct/Destruct + public: + + /** + * This constructor is suitable for creating an object group from + * scratch. + */ + FT_PG_Object_Group_Storable ( + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + CORBA::Object_ptr empty_group, + const PortableGroup::TagGroupTaggedComponent & tagged_component, + const char * type_id, + const PortableGroup::Criteria & the_criteria, + TAO::PG_Property_Set * type_properties, + TAO::Storable_Factory & storable_factory); + + /** + * This constructor is suitable for creating an object group from + * persistent store. + */ + FT_PG_Object_Group_Storable ( + PortableGroup::ObjectGroupId group_id, + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + TAO::Storable_Factory & storable_factory); + + /// Destructor + ~FT_PG_Object_Group_Storable (); + + ///////////////// + // public methods + + public: + + virtual void stale (bool is_stale); + virtual bool stale (); + + protected: + + virtual void state_written (); + + virtual bool is_obsolete (time_t stored_time); + + /// Provide support for modifying the object group type_id when first + /// member is added to the group. + virtual PortableGroup::ObjectGroup_ptr add_member_to_iogr( + CORBA::Object_ptr member); + + private: + + ///////////////////////// + // Forbidden methods + FT_PG_Object_Group_Storable (); + FT_PG_Object_Group_Storable (const FT_PG_Object_Group_Storable & rhs); + FT_PG_Object_Group_Storable & operator = ( + const FT_PG_Object_Group_Storable & rhs); + + /// Replication persistence support + + bool stale_; + + /// Track if the persistent file used for storage has been created yet + /// so can know if we should propagate a change type of NEW. + bool file_created_; + + /** + * Although it is assumed for replication that services + * using object groups share the persistent store, a + * CORBA message is sent upon update from one replica to + * another so the object group data can be marked as stale. + * This is because using the file time stamp to detect + * if the data has been updated only provides one second + * resolution. + */ + int propagate_update_notification (FT_Naming::ChangeType change_type); + + }; +} // namespace TAO + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif // FT_TAO_PG_OBJECT_GROUP_STORABLE_H_ diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context.cpp b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context.cpp new file mode 100644 index 00000000000..ab1a1ae2737 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context.cpp @@ -0,0 +1,111 @@ +// $Id$ + +#include "orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.h" +#include "orbsvcs/FT_NamingManagerC.h" +#include "orbsvcs/PortableGroup/PG_Utils.h" +#include "orbsvcs/PortableGroup/PG_Property_Utils.h" + +#include "orbsvcs/Naming/Persistent_Context_Index.h" +#include "ace/OS_NS_stdio.h" + +#include "ace/Auto_Ptr.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +// Initialize the static naming manager +TAO_FT_Naming_Manager *TAO_FT_Persistent_Naming_Context::naming_manager_impl_ = 0; + +TAO_FT_Persistent_Naming_Context::TAO_FT_Persistent_Naming_Context ( + PortableServer::POA_ptr poa, + const char *poa_id, + TAO_Persistent_Context_Index *context_index, + HASH_MAP *map, + ACE_UINT32 *counter) + : TAO_Persistent_Naming_Context (poa, + poa_id, + context_index, + map, + counter) +{ + +} + + +TAO_FT_Persistent_Naming_Context::~TAO_FT_Persistent_Naming_Context (void) +{ + // Perform appropriate cleanup based on the destruction level specified. +} + + +CORBA::Boolean +TAO_FT_Persistent_Naming_Context::is_object_group (CORBA::Object_ptr obj) const +{ + // If there is a tagged component with tag = IOP::TAG_FT_GROUP in + // the object reference then it is an object group + PortableGroup::TagGroupTaggedComponent tagged_component; + return TAO::PG_Utils::get_tagged_component (obj, tagged_component); +} + +CORBA::Object_ptr +TAO_FT_Persistent_Naming_Context::resolve (const CosNaming::Name& n) +{ + // Invoke the base class resolve operation to acquire the object at the + // specified compound name. + // Any exceptions should flow back to client. + CORBA::Object_var resolved_ref = + TAO_Persistent_Naming_Context::resolve(n); + + ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, + CORBA::INTERNAL ()); + + // Get the locations of the object group members and we will use them to + // do the load balancing + try { + + // Make sure object is an object group. + // We will return the object reference all the way back out to the client + // if not + if (!this->is_object_group (resolved_ref.in ())) + return resolved_ref._retn (); + + // If there is no naming manager, we will fail and report an error. + if ( this->naming_manager_impl_ == 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("TAO_FT_Persistent_Naming_Context::resolve ") + ACE_TEXT ("- No NamingManager defined.\n"))); + + throw CORBA::INTERNAL (); + } + + // The Naming Manager will apply the appropriate strategy to get the + // next object reference from the object group. + resolved_ref = this->naming_manager_impl_->next_member (resolved_ref.in ()); + } + catch (const PortableGroup::ObjectGroupNotFound&) + { + // This is apparently not an object group, so we should return the + // object reference itself + // No action required + } + catch (CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("TAO_FT_Persistent_Naming_Context::resolve ") + ACE_TEXT ("- Some unhandled error occurred\n")); + return CORBA::Object::_nil (); + } + + return resolved_ref._retn (); +} + +void +TAO_FT_Persistent_Naming_Context::set_naming_manager_impl ( + TAO_FT_Naming_Manager *mgr_impl) +{ + naming_manager_impl_ = (mgr_impl); +} + + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context.h new file mode 100644 index 00000000000..1303c78daae --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context.h @@ -0,0 +1,75 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_Persistent_Naming_Context.h + * + * $Id$ + * + * @author Kevin Stanley <stanleyk@ociweb.com> + */ +//============================================================================= + + +#ifndef TAO_FT_PERSISTENT_NAMING_CONTEXT_H +#define TAO_FT_PERSISTENT_NAMING_CONTEXT_H +#include /**/ "ace/pre.h" + +#include "orbsvcs/Naming/Persistent_Naming_Context.h" +#include "orbsvcs/Naming/FaultTolerant/ftnaming_export.h" +#include "orbsvcs/orbsvcs/PortableGroupC.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class TAO_FT_Persistent_Naming_Context + * + * @brief This class specializes the TAO_Persistent_Naming_Context + * 'ConcreteImplementor' in the Bridge pattern architecture of the + * CosNaming::NamingContext implementation. + * + */ +class TAO_FtNaming_Export TAO_FT_Persistent_Naming_Context : + public TAO_Persistent_Naming_Context +{ +public: + /// Underlying data structure - typedef for ease of use. + typedef TAO_Persistent_Naming_Context::HASH_MAP HASH_MAP; + + // = Initialization and termination methods. + + /** + * Constructor that takes in preallocated data structure and takes + * ownership of it. Derived class from TAO_Persistent_Naming_Context + * provides specialization of the resolve operation to support + * load balancing. + */ + TAO_FT_Persistent_Naming_Context (PortableServer::POA_ptr poa, + const char *poa_id, + TAO_Persistent_Context_Index *context_index, + HASH_MAP * map = 0, + ACE_UINT32 *counter = 0); + + /// Destructor. + virtual ~TAO_FT_Persistent_Naming_Context (void); + + /** + * Override the resolve operation to support load balancing using + * the object group manager and associated strategy. + */ + virtual CORBA::Object_ptr resolve (const CosNaming::Name &n); + + static void set_naming_manager_impl (TAO_FT_Naming_Manager *mgr_impl); + + bool is_object_group (const CORBA::Object_ptr obj) const; + +protected: + static TAO_FT_Naming_Manager *naming_manager_impl_; + +}; + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* TAO_FT_PERSISTENT_NAMING_CONTEXT_H */ diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context_Factory.cpp b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context_Factory.cpp new file mode 100644 index 00000000000..5ba6a1d38c4 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context_Factory.cpp @@ -0,0 +1,40 @@ +// $Id$ + +#include "orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context_Factory.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + + /// Constructor. +TAO_FT_Persistent_Naming_Context_Factory::TAO_FT_Persistent_Naming_Context_Factory (void) +: TAO_Persistent_Naming_Context_Factory () +{ + +} + + /// Destructor. Does not deallocate the hash map: if an instance of + /// this class goes out of scope, its hash_map remains in persistent storage. +TAO_FT_Persistent_Naming_Context_Factory::~TAO_FT_Persistent_Naming_Context_Factory (void) +{ +} + + +/// Factory method for creating an implementation object for naming contexts +TAO_Persistent_Naming_Context* +TAO_FT_Persistent_Naming_Context_Factory::create_naming_context_impl ( + PortableServer::POA_ptr poa, + const char *poa_id, + TAO_Persistent_Context_Index *context_index, + HASH_MAP * map, + ACE_UINT32 *counter) +{ + // Construct the naming context, forwarding the map and counter even if they + // are defaulted + return new (ACE_nothrow) TAO_FT_Persistent_Naming_Context (poa, + poa_id, + context_index, + map, + counter); +} + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context_Factory.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context_Factory.h new file mode 100644 index 00000000000..bebf02fdbc7 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Persistent_Naming_Context_Factory.h @@ -0,0 +1,56 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_Persistent_Naming_Context_Factory.h + * + * $Id$ + * + * @author Kevin Stanley stanleyk@ociweb.com> + */ +//============================================================================= + + +#ifndef TAO_FT_PERSISTENT_NAMING_CONTEXT_FACTORY_H +#define TAO_FT_PERSISTENT_NAMING_CONTEXT_FACTORY_H +#include /**/ "ace/pre.h" + +#include "orbsvcs/Naming/Persistent_Naming_Context_Factory.h" +#include "orbsvcs/Naming/FaultTolerant/ftnaming_export.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class TAO_FT_Persistent_Naming_Context_Factory + * + * @brief An implementation of the TAO_Naming_Context_Factory that creates + * TAO_FT_Persistent_Naming_Context to implement the COS Naming Service + * NamingContext interface. + */ +class TAO_FtNaming_Export TAO_FT_Persistent_Naming_Context_Factory + : public TAO_Persistent_Naming_Context_Factory +{ +public: + + // = Initialization and termination methods. + + /// Constructor. + TAO_FT_Persistent_Naming_Context_Factory (void); + + /// Destructor. Does not deallocate the hash map: if an instance of + /// this class goes out of scope, its hash_map remains in persistent storage. + virtual ~TAO_FT_Persistent_Naming_Context_Factory (void); + + /// Factory method for creating an implementation object for naming contexts + virtual TAO_Persistent_Naming_Context* create_naming_context_impl ( + PortableServer::POA_ptr poa, + const char *poa_id, + TAO_Persistent_Context_Index *context_index, + HASH_MAP * map = 0, + ACE_UINT32 *counter = 0); +}; + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* TAO_FT_PERSISTENT_NAMING_CONTEXT_FACTORY_H */ diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Round_Robin.cpp b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Round_Robin.cpp new file mode 100644 index 00000000000..132d2a25d3a --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Round_Robin.cpp @@ -0,0 +1,76 @@ +// -*- C++ -*- +// $Id$ + +#include "orbsvcs/Naming/FaultTolerant/FT_Round_Robin.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.h" + +#include "orbsvcs/PortableGroup/PG_conf.h" + +#include "tao/debug.h" +#include "tao/ORB_Constants.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +TAO_FT_Round_Robin::TAO_FT_Round_Robin (void) + : lock_ (), + location_index_map_ (TAO_PG_MAX_OBJECT_GROUPS) +{ +} + +TAO_FT_Round_Robin::~TAO_FT_Round_Robin (void) +{ +} + + +bool +TAO_FT_Round_Robin::next_location ( + PortableGroup::ObjectGroup_ptr object_group, + TAO_FT_Naming_Manager *naming_manager, + PortableGroup::Location& location) +{ + const PortableGroup::ObjectGroupId id = + naming_manager->get_object_group_id (object_group); + + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + monitor, + this->lock_, + 0); + + PortableGroup::Locations_var locations = + naming_manager->locations_of_members (object_group); + + const CORBA::ULong len = locations->length (); + + // No locations exist, so we can't get the next one + if (len == 0) + return false; + + TAO_FT_Location_Index_Map::ENTRY * entry; + if (this->location_index_map_.find (id, entry) == 0) + { + CORBA::ULong & i = entry->int_id_; + + if (len <= i) + i = 0; // Reset, i.e. wrap around + + location = locations[i]; + + // Increment index to point to next location. + ++i; + + return true; + } + + // Could not find an entry + // Create an entry at location 0 + CORBA::ULong start = 0; + location = locations[start++]; + if (this->location_index_map_.bind (id, start) != 0) + { // The location was already bound or some failure occured. Should not happen. + throw CORBA::INTERNAL (); + } + return true; +} + + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Round_Robin.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Round_Robin.h new file mode 100644 index 00000000000..3708771bba8 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Round_Robin.h @@ -0,0 +1,95 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_Round_Robin.h + * + * $Id$ + * + * @author Kevin Stanley <stanleyk@ociweb.com> + */ +//============================================================================= + + +#ifndef FT_ROUND_ROBIN_H +#define FT_ROUND_ROBIN_H + +#include /**/ "ace/pre.h" + +#include "ace/Null_Mutex.h" + +# if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +# endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "orbsvcs/Naming/FaultTolerant/FT_Location_Index_Map.h" + + +#include "orbsvcs/CosLoadBalancingS.h" +#include "ace/Vector_T.h" +#include "orbsvcs/Naming/FaultTolerant/ftnaming_export.h" + +class TAO_FT_Naming_Manager; + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class TAO_LB_RoundRobin_Strategy + * + * @brief "Round Robin" load balancing strategy used by the + * TAO_FT_Naming_Service. + * + * This load balancing strategy is designed to select an object group + * member residing at the next location from an object group managed + * by a specific Naming Manager. It selects an object from the object + * group in the order in which they are stored. + */ +class TAO_FtNaming_Export TAO_FT_Round_Robin +{ +public: + + /// Constructor. + TAO_FT_Round_Robin (void); + + /// This function obtains the next object's location as it is bound + /// within the object group. + /// @param naming_manager The TAO_FT_Naming_Manager which houses the + /// object groups. + /// @param location The resulting location + /// @param object_group The object group from which the object is to + /// be selected + /// @return False on error. Returns true if a valid object can + /// be selected using the Round Robin load balancing strategy. + virtual bool next_location ( + PortableGroup::ObjectGroup_ptr object_group, + TAO_FT_Naming_Manager *naming_manager, + PortableGroup::Location& location); + + /// Destructor + virtual ~TAO_FT_Round_Robin (void); + +private: + + /// Lock used to ensure atomic access to state retained by this + /// class. + TAO_SYNCH_MUTEX lock_; + + /// Table that maps PortableGroup::ObjectGroupId to location + /// sequence index specific to a given object group. + /** + * The location sequence corresponds to the sequence containing the + * locations of the members of a given object group. The value + * stored in this map corresponds to the index of the next element + * in that sequence. For example, if the index stored in the map is + * 2, location[2] will be used when retrieving the object reference + * to be returned from the Strategy::next_member() method. + */ + TAO_FT_Location_Index_Map location_index_map_; + +}; + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* FT_ROUND_ROBIN_H */ diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context.cpp b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context.cpp new file mode 100644 index 00000000000..653b4ef90c0 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context.cpp @@ -0,0 +1,183 @@ +// $Id$ + +#include "orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Replication_Manager.h" +#include "orbsvcs/FT_NamingManagerC.h" +#include "orbsvcs/PortableGroup/PG_Utils.h" +#include "orbsvcs/PortableGroup/PG_Property_Utils.h" + +#include "orbsvcs/Naming/Persistent_Context_Index.h" +#include "ace/OS_NS_stdio.h" + +#include "ace/Auto_Ptr.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +// Initialize the static naming manager +TAO_FT_Naming_Manager *TAO_FT_Storable_Naming_Context::naming_manager_ = 0; + +TAO_FT_Storable_Naming_Context::TAO_FT_Storable_Naming_Context (CORBA::ORB_ptr orb, + PortableServer::POA_ptr poa, + const char *poa_id, + TAO_Storable_Naming_Context_Factory *cxt_factory, + TAO::Storable_Factory *pers_factory) + : TAO_Storable_Naming_Context (orb, + poa, + poa_id, + cxt_factory, + pers_factory), + stale_ (false) +{ + +} + + +TAO_FT_Storable_Naming_Context::~TAO_FT_Storable_Naming_Context (void) +{ + // Perform appropriate cleanup based on the destruction level specified. +} + + +CORBA::Boolean +TAO_FT_Storable_Naming_Context::is_object_group (CORBA::Object_ptr obj) const +{ + // Ensure the object is not nil first. If so, it cannot be an ObjectGroup. + if (CORBA::is_nil (obj)) + return 0; + + // If there is a tagged component with tag = IOP::TAG_FT_GROUP in the + // object reference then it is an object group + PortableGroup::TagGroupTaggedComponent tagged_component; + return TAO::PG_Utils::get_tagged_component (obj, tagged_component); +} + +CORBA::Object_ptr +TAO_FT_Storable_Naming_Context::resolve (const CosNaming::Name& n) +{ + // Invoke the base class resolve operation to acquire the object at the + // specified compound name. Any exceptions should flow back to client. + CORBA::Object_var resolved_ref = + TAO_Storable_Naming_Context::resolve(n); + + ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, + CORBA::INTERNAL ()); + + try { + + // Make sure object is an object group. + // We will return the object reference as is all the way back + // out to the client if not + if (!this->is_object_group (resolved_ref.in ())) + return resolved_ref._retn (); + + // If there is no naming manager, we will fail and report an error. + if ( this->naming_manager_ == 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("TAO_FT_Storable_Naming_Context::resolve ") + ACE_TEXT ("- No NamingManager defined.\n"))); + + throw CORBA::INTERNAL (); + } + + // The Naming Manager will apply the appropriate strategy to get the + // next object reference from the object group. + resolved_ref = this->naming_manager_->next_member (resolved_ref.in ()); + } + catch (const PortableGroup::ObjectGroupNotFound&) + { + // This is apparently not an object group, so we should return the + // object reference itself + // No action required + } + catch (CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("TAO_FT_Storable_Naming_Context::resolve - ") + ACE_TEXT ("Some unhandled error occurred\n")); + return CORBA::Object::_nil (); + } + + return resolved_ref._retn (); +} + +int +TAO_FT_Storable_Naming_Context::propagate_update_notification ( + FT_Naming::ChangeType change_type) +{ + // Notify the peer of the changed context + FT_Naming::ReplicationManager_var peer = + TAO_FT_Naming_Replication_Manager::peer_replica (); + + if (CORBA::is_nil (peer.in ())) + { + // Replication is not supported without a peer replica. + return 1; + } + + FT_Naming::NamingContextUpdate context_info; + context_info.context_name = this->context_name_.c_str (); + + // We are are updating the context one element before the specified name + context_info.change_type = change_type; + + try { + // Notify the naming_manager of the updated context + peer->notify_updated_context (context_info); + } + catch (CORBA::Exception& ex) + { + if (TAO_debug_level > 3) + ex._tao_print_exception (ACE_TEXT ("Unable to communicate with peer.\n")); + return -1; + } + + return 0; +} + +void +TAO_FT_Storable_Naming_Context::set_naming_manager ( + TAO_FT_Naming_Manager *mgr_impl) +{ + naming_manager_ = mgr_impl; +} + +void +TAO_FT_Storable_Naming_Context::stale (bool is_stale) +{ + this->stale_ = is_stale; +} + + +bool +TAO_FT_Storable_Naming_Context::stale (void) +{ + return stale_; +} + + +void +TAO_FT_Storable_Naming_Context::context_written (void) +{ + FT_Naming::ChangeType change_type; + + if (this->destroyed_) + change_type = FT_Naming::DELETED; + else + change_type = FT_Naming::UPDATED; + + propagate_update_notification (change_type); +} + +bool +TAO_FT_Storable_Naming_Context::is_obsolete (time_t stored_time) +{ + // If data has never been loaded, then the context_ object will + // be a null pointer. + return ((this->context_ == 0) || // Has not been loaded + this->stale () || // Explicitly marked stale by peer + (stored_time > this->last_changed_)); // File has been updated +} + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context.h new file mode 100644 index 00000000000..96b0f4d0317 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context.h @@ -0,0 +1,112 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_Storable_Naming_Context.h + * + * $Id$ + * + * @author Kevin Stanley <stanleyk@ociweb.com> + */ +//============================================================================= + + +#ifndef TAO_FT_STORABLE_NAMING_CONTEXT_H +#define TAO_FT_STORABLE_NAMING_CONTEXT_H +#include /**/ "ace/pre.h" + +#include "orbsvcs/Naming/Storable_Naming_Context.h" +#include "orbsvcs/Naming/FaultTolerant/ftnaming_export.h" +#include "orbsvcs/orbsvcs/PortableGroupC.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Naming_Manager.h" +#include "orbsvcs/FT_NamingReplicationC.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class FT_TAO_Storable_Naming_Context + * + * @brief This class specializes the TAO_Storable_Naming_Context + * 'ConcreteImplementor' in the Bridge pattern architecture of the + * CosNaming::NamingContext implementation. + * + */ +class TAO_FtNaming_Export TAO_FT_Storable_Naming_Context : + public TAO_Storable_Naming_Context +{ +public: + // = Initialization and termination methods. + + /** + * Constructor that takes in preallocated data structure and takes + * ownership of it. Derived class from TAO_Persistent_Naming_Context + * provides specialization of the resolve operation to support + * load balancing. + */ + TAO_FT_Storable_Naming_Context (CORBA::ORB_ptr orb, + PortableServer::POA_ptr poa, + const char *poa_id, + TAO_Storable_Naming_Context_Factory *cxt_factory, + TAO::Storable_Factory *factory); + + /// Destructor. + virtual ~TAO_FT_Storable_Naming_Context (void); + + /** + * Override the resolve operation to support load balancing using + * the object group manager and associated strategy. + */ + virtual CORBA::Object_ptr resolve (const CosNaming::Name &n); + + // Set the Naming Manager as a static so that it is available for all + // naming context implementations. + static void set_naming_manager (TAO_FT_Naming_Manager *mgr_impl); + + bool is_object_group (const CORBA::Object_ptr obj) const; + + /** + * Tell the peer replica that this context has been updated. + * Returns 0 if successfully reported. Returns 1 if no peer + * has been registered. Returns -1 on failure to communicate + * with the peer. + */ + int propagate_update_notification (FT_Naming::ChangeType change_type); + + /** + * Find the indicated context below this context. Returns 0 + * if it cannot be found. + */ + TAO_FT_Storable_Naming_Context* find_relative_context ( + const CosNaming::Name &n); + + /** + * Mark the implementation as stale for replicated persistence support. + */ + virtual void stale (bool is_stale); + + virtual bool stale (void); + + /** + * An internal utility used to signal that this context was updated. + * Check the last_changed_ attribute for the time of the write. + */ + void context_written (void); + + /** + * An internal callback invoked by the File_Open_Lock_and_Check + * object to determine if this context is obsolete with respect to the + * file object . + */ + virtual bool is_obsolete (time_t stored_time); + +protected: + + static TAO_FT_Naming_Manager *naming_manager_; + bool stale_; + +}; + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* TAO_FT_STORABLE_NAMING_CONTEXT_H */ diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context_Factory.cpp b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context_Factory.cpp new file mode 100644 index 00000000000..9a35f407ab7 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context_Factory.cpp @@ -0,0 +1,47 @@ +// $Id$ + +#include "orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context_Factory.h" +#include "orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + + /// Constructor. +TAO_FT_Storable_Naming_Context_Factory::TAO_FT_Storable_Naming_Context_Factory ( + size_t hash_table_size) + : TAO_Storable_Naming_Context_Factory (hash_table_size) +{ + +} + + /// Destructor. Does not deallocate the hash map: if an instance of + /// this class goes out of scope, its hash_map remains in persistent storage. +TAO_FT_Storable_Naming_Context_Factory::~TAO_FT_Storable_Naming_Context_Factory (void) +{ + +} + + +TAO_Storable_Naming_Context* +TAO_FT_Storable_Naming_Context_Factory::create_naming_context_impl ( + CORBA::ORB_ptr orb, + PortableServer::POA_ptr poa, + const char *poa_id, + TAO::Storable_Factory *persistence_factory + ) +{ + // Construct the naming context, forwarding the map and counter + // even if they are defaulted + TAO_FT_Storable_Naming_Context *context_impl; + ACE_NEW_THROW_EX (context_impl, + TAO_FT_Storable_Naming_Context (orb, + poa, + poa_id, + this, + persistence_factory), + CORBA::NO_MEMORY ()); + + return context_impl; +} + + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context_Factory.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context_Factory.h new file mode 100644 index 00000000000..b714d052914 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/FT_Storable_Naming_Context_Factory.h @@ -0,0 +1,66 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FT_Storable_Naming_Context_Factory.h + * + * $Id$ + * + * @author Kevin Stanley stanleyk@ociweb.com> + */ +//============================================================================= + + +#ifndef TAO_FT_STORABLE_NAMING_CONTEXT_FACTORY_H +#define TAO_FT_STORABLE_NAMING_CONTEXT_FACTORY_H +#include /**/ "ace/pre.h" + +#include "orbsvcs/Naming/Storable_Naming_Context_Factory.h" +#include "tao/ORB.h" +#include "orbsvcs/Naming/nsconf.h" +#include "orbsvcs/Naming/FaultTolerant/ftnaming_export.h" +#include "orbsvcs/Naming/Hash_Naming_Context.h" +#include "orbsvcs/Naming/Storable_Naming_Context.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class TAO_Naming_Context_Factory + * + * @brief + */ +class TAO_FtNaming_Export TAO_FT_Storable_Naming_Context_Factory : + public TAO_Storable_Naming_Context_Factory +{ +public: + + /// Data structure used by TAO_Persistent_Context_Index - + /// typedef for ease of use. + typedef TAO_Storable_Naming_Context_Factory::HASH_MAP HASH_MAP; + + // = Initialization and termination methods. + + /// Constructor. + TAO_FT_Storable_Naming_Context_Factory ( + size_t hash_table_size = ACE_DEFAULT_MAP_SIZE); + + /// Destructor. Does not deallocate the hash map: if an instance of + /// this class goes out of scope, its hash_map remains in persistent storage. + virtual ~TAO_FT_Storable_Naming_Context_Factory (void); + + /// Factory method for creating an implementation object for naming contexts. + /// If an existing naming context implementation is being rebuilt, + /// the map and counter parameters should be provided to the underlying + /// HASH_MAP implementation + virtual TAO_Storable_Naming_Context* create_naming_context_impl ( + CORBA::ORB_ptr orb, + PortableServer::POA_ptr poa, + const char *poa_id, + TAO::Storable_Factory *factory); + +}; + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* TAO_FT_STORABLE_NAMING_CONTEXT_FACTORY_H */ diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/ftnaming_export.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/ftnaming_export.h new file mode 100644 index 00000000000..e8a204363c9 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/ftnaming_export.h @@ -0,0 +1,58 @@ + +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl TAO_FtNaming +// ------------------------------ +#ifndef TAO_FTNAMING_EXPORT_H +#define TAO_FTNAMING_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (TAO_FTNAMING_HAS_DLL) +# define TAO_FTNAMING_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && TAO_FTNAMING_HAS_DLL */ + +#if !defined (TAO_FTNAMING_HAS_DLL) +# define TAO_FTNAMING_HAS_DLL 1 +#endif /* ! TAO_FTNAMING_HAS_DLL */ + +#if defined (TAO_FTNAMING_HAS_DLL) && (TAO_FTNAMING_HAS_DLL == 1) +# if defined (TAO_FTNAMING_BUILD_DLL) +# define TAO_FtNaming_Export ACE_Proper_Export_Flag +# define TAO_FTNAMING_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define TAO_FTNAMING_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* TAO_FTNAMING_BUILD_DLL */ +# define TAO_FtNaming_Export ACE_Proper_Import_Flag +# define TAO_FTNAMING_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define TAO_FTNAMING_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* TAO_FTNAMING_BUILD_DLL */ +#else /* TAO_FTNAMING_HAS_DLL == 1 */ +# define TAO_FtNaming_Export +# define TAO_FTNAMING_SINGLETON_DECLARATION(T) +# define TAO_FTNAMING_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* TAO_FTNAMING_HAS_DLL == 1 */ + +// Set TAO_FTNAMING_NTRACE = 0 to turn on library specific tracing even if +// tracing is turned off for ACE. +#if !defined (TAO_FTNAMING_NTRACE) +# if (ACE_NTRACE == 1) +# define TAO_FTNAMING_NTRACE 1 +# else /* (ACE_NTRACE == 1) */ +# define TAO_FTNAMING_NTRACE 0 +# endif /* (ACE_NTRACE == 1) */ +#endif /* !TAO_FTNAMING_NTRACE */ + +#if (TAO_FTNAMING_NTRACE == 1) +# define TAO_FTNAMING_TRACE(X) +#else /* (TAO_FTNAMING_NTRACE == 1) */ +# if !defined (ACE_HAS_TRACE) +# define ACE_HAS_TRACE +# endif /* ACE_HAS_TRACE */ +# define TAO_FTNAMING_TRACE(X) ACE_TRACE_IMPL(X) +# include "ace/Trace.h" +#endif /* (TAO_FTNAMING_NTRACE == 1) */ + +#endif /* TAO_FTNAMING_EXPORT_H */ + +// End of auto generated file. diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/ftnaming_intf_export.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/ftnaming_intf_export.h new file mode 100644 index 00000000000..6b52adde64a --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/ftnaming_intf_export.h @@ -0,0 +1,58 @@ + +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl TAO_FtNaming_Intf +// ------------------------------ +#ifndef TAO_FTNAMING_INTF_EXPORT_H +#define TAO_FTNAMING_INTF_EXPORT_H + +#include "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (TAO_FTNAMING_INTF_HAS_DLL) +# define TAO_FTNAMING_INTF_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && TAO_FTNAMING_INTF_HAS_DLL */ + +#if !defined (TAO_FTNAMING_INTF_HAS_DLL) +# define TAO_FTNAMING_INTF_HAS_DLL 1 +#endif /* ! TAO_FTNAMING_INTF_HAS_DLL */ + +#if defined (TAO_FTNAMING_INTF_HAS_DLL) && (TAO_FTNAMING_INTF_HAS_DLL == 1) +# if defined (TAO_FTNAMING_INTF_BUILD_DLL) +# define TAO_FtNaming_Intf_Export ACE_Proper_Export_Flag +# define TAO_FTNAMING_INTF_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define TAO_FTNAMING_INTF_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* TAO_FTNAMING_INTF_BUILD_DLL */ +# define TAO_FtNaming_Intf_Export ACE_Proper_Import_Flag +# define TAO_FTNAMING_INTF_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define TAO_FTNAMING_INTF_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* TAO_FTNAMING_INTF_BUILD_DLL */ +#else /* TAO_FTNAMING_INTF_HAS_DLL == 1 */ +# define TAO_FtNaming_Intf_Export +# define TAO_FTNAMING_INTF_SINGLETON_DECLARATION(T) +# define TAO_FTNAMING_INTF_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* TAO_FTNAMING_INTF_HAS_DLL == 1 */ + +// Set TAO_FTNAMING_INTF_NTRACE = 0 to turn on library specific tracing even if +// tracing is turned off for ACE. +#if !defined (TAO_FTNAMING_INTF_NTRACE) +# if (ACE_NTRACE == 1) +# define TAO_FTNAMING_INTF_NTRACE 1 +# else /* (ACE_NTRACE == 1) */ +# define TAO_FTNAMING_INTF_NTRACE 0 +# endif /* (ACE_NTRACE == 1) */ +#endif /* !TAO_FTNAMING_INTF_NTRACE */ + +#if (TAO_FTNAMING_INTF_NTRACE == 1) +# define TAO_FTNAMING_INTF_TRACE(X) +#else /* (TAO_FTNAMING_INTF_NTRACE == 1) */ +# if !defined (ACE_HAS_TRACE) +# define ACE_HAS_TRACE +# endif /* ACE_HAS_TRACE */ +# define TAO_FTNAMING_INTF_TRACE(X) ACE_TRACE_IMPL(X) +# include "ace/Trace.h" +#endif /* (TAO_FTNAMING_INTF_NTRACE == 1) */ + +#endif /* TAO_FTNAMING_INTF_EXPORT_H */ + +// End of auto generated file. diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/nsgroup_svc.cpp b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/nsgroup_svc.cpp new file mode 100644 index 00000000000..bc134bd8626 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/nsgroup_svc.cpp @@ -0,0 +1,717 @@ +//============================================================================= +/** + * @file nsgroup_svc.cpp + * + * $Id$ + * + * This file implements nsgroup utility operations + * + * @author Phillip LaBanca <labancap@ociweb.com> + */ +//============================================================================= + +#include "orbsvcs/Naming/FaultTolerant/nsgroup_svc.h" +#include "ace/OS_NS_strings.h" + + +NS_group_svc::NS_group_svc (void) +{ +} + +FT_Naming::LoadBalancingStrategyValue +NS_group_svc::determine_policy_string (const ACE_TCHAR *policy) +{ + if (ACE_OS::strcasecmp (policy, + ACE_TEXT_ALWAYS_CHAR ("rand")) == 0) { + return FT_Naming::RANDOM; + } else if (ACE_OS::strcasecmp (policy, + ACE_TEXT_ALWAYS_CHAR ("least")) == 0) { + return FT_Naming::LEAST; + } else { + return FT_Naming::ROUND_ROBIN; // Default case + } +} + +int +NS_group_svc::set_orb( CORBA::ORB_ptr orb) +{ + + this->orb_ = CORBA::ORB::_duplicate (orb); + + if (CORBA::is_nil (this->orb_)) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT (" (%P|%t) Unable to initialize the ") + ACE_TEXT ("ORB.\n")), + -1); + return 0; +} + +int +NS_group_svc::set_naming_manager( FT_Naming::NamingManager_ptr nm) +{ + + this->naming_manager_ = FT_Naming::NamingManager::_duplicate (nm); + + if (CORBA::is_nil (this->naming_manager_)) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT (" (%P|%t) Invalid Naming Manager.\n")), + -1); + return 0; +} + +int +NS_group_svc::set_name_context( CosNaming::NamingContextExt_ptr nc) +{ + + this->name_service_ = CosNaming::NamingContextExt::_duplicate (nc); + + if (CORBA::is_nil (this->name_service_)) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT (" (%P|%t) Invalid Name Context.\n")), + -1); + return 0; +} + +bool +NS_group_svc::group_exist ( + const ACE_TCHAR* group_name +) +{ + if (group_name == 0 ) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("group_exist args not provided\n")), + false); + } + + try + { + PortableGroup::ObjectGroup_var group_var = + this->naming_manager_->get_object_group_ref_from_name (group_name); + } + catch (const PortableGroup::ObjectGroupNotFound&) + { + return false; + } + + return true; +} + +/** + * The naming service shall provide a command line utility for creating + * object groups. Adds the object group to to the load balancing service + * with the specified selection policy. On Creation, an object group + * contains no member objects. + */ + +int +NS_group_svc::group_create ( + const ACE_TCHAR* group_name, + const ACE_TCHAR* policy ) +{ + + if (group_name == 0 || policy == 0 ) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("group_create args not provided\n")), + -2); + } + + try + { + + /// Verify that the group does not already exist + /// Group names must be unique + if ( true == group_exist (ACE_TEXT_ALWAYS_CHAR (group_name))) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Group %C already exists\n"), + group_name), + -1); + } + + PortableGroup::Criteria criteria (1); + criteria.length (1); + + PortableGroup::Property &property = criteria[0]; + property.nam.length (1); + + property.nam[0].id = CORBA::string_dup ( + ACE_TEXT_ALWAYS_CHAR ("org.omg.PortableGroup.MembershipStyle")); + + PortableGroup::MembershipStyleValue msv = PortableGroup::MEMB_APP_CTRL; + property.val <<= msv; + + CORBA::Object_var obj = + this->naming_manager_->create_object_group ( + ACE_TEXT_ALWAYS_CHAR (group_name), + determine_policy_string(ACE_TEXT_ALWAYS_CHAR (policy)), + criteria); + + if (CORBA::is_nil (obj.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to create group %C.\n"), + group_name), + -1); + } + + } + catch (const CORBA::Exception&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to create group %C\n"), + group_name), + -1); + } + + return 0; +} + +/** + * The naming service shall provide a command line utility for binding an object + * group to a path in the naming service. + * Binds the specified object group to the specified path in the naming service. + * When clients resolve that path, they tranparently obtain a member of the + * specified object group. + */ +int +NS_group_svc::group_bind ( + const ACE_TCHAR* group_name, + const ACE_TCHAR* path) +{ + + if (group_name == 0 || path == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("group_bind args not provided\n")), + -2); + } + + try + { + + PortableGroup::ObjectGroup_var group_var = + this->naming_manager_->get_object_group_ref_from_name ( + ACE_TEXT_ALWAYS_CHAR(group_name)); + + if (CORBA::is_nil (group_var.in())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Unable to get reference.\n")), + -1); + + CORBA::String_var str = CORBA::string_dup( ACE_TEXT_ALWAYS_CHAR (path) ); + CosNaming::Name_var name = this->name_service_->to_name ( str.in() ); + + this->name_service_->rebind (name.in(), group_var.in()); + + } + catch (const CosNaming::NamingContextExt::InvalidName& ex){ + ex._tao_print_exception ("InvalidName Exception in group_bind"); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\n%C is invalid\n"), + path), + -1); + } + catch (const CosNaming::NamingContext::CannotProceed&){ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nCannot proceed with %C\n"), + path), + -1); + } + catch (const CosNaming::NamingContext::NotFound&){ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to find %C\n"), + path), + -1); + } + catch (const CORBA::SystemException& ex){ + + ex._tao_print_exception ("SystemException Exception in group_bind"); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to bind %C\n"), + path), + -1); + } + catch (const CORBA::Exception& ex){ + + ex._tao_print_exception ("Exception in group_bind"); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to bind %C\n"), + path), + -1); + } + return 0; +} + +int +NS_group_svc::group_unbind (const ACE_TCHAR* path){ + if ( path == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("group_unbind args not provided\n")), + -2); + } + + try + { + + CORBA::String_var str = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR (path)); + CosNaming::Name_var name = this->name_service_->to_name ( str.in() ); + this->name_service_->unbind (name.in()); + + } + catch (const CosNaming::NamingContext::NotFound&){ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to find %C\n"), + path), + -1); + } + catch (const CosNaming::NamingContext::CannotProceed&){ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nCannot proceed with %C\n"), + path), + -1); + } + catch (const CosNaming::NamingContext::InvalidName&) { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\n%C is invalid\n"), + path), + -1); + } + catch (const CORBA::SystemException& ex) { + + ex._tao_print_exception ("Exception in group_unbind"); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to unbind %C\n"), + path), + -1); + } + catch (const CORBA::Exception& ex) { + + ex._tao_print_exception ("Exception in group_unbind"); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to unbind %C\n"), + path), + -1); + } + return 0; +} + +/** + * The naming service shall provide a command line utility to display all + * defined object groups within the naming service. + * Displays all object groups that currently exist in the naming service. + */ +int +NS_group_svc::group_list (void) +{ + + // KCS: The group list is independent of locations. I created a new operation in the + // naming manager IDL to support requesting the group list - which is a list of names + + /// Display object group list for each load balancing strategy + int rc = 0; + if( display_load_policy_group (FT_Naming::ROUND_ROBIN, + ACE_TEXT ("Round Robin")) < 0 ) + { + rc = -1; + } + if( display_load_policy_group (FT_Naming::RANDOM, + ACE_TEXT ("Random")) < 0 ) + { + rc = -1; + } + if( display_load_policy_group (FT_Naming::LEAST, + ACE_TEXT ("Least")) < 0 ) + { + rc = -1; + } + return rc; +} + +int +NS_group_svc::display_load_policy_group( + FT_Naming::LoadBalancingStrategyValue strategy, + const ACE_TCHAR *display_label) { + + if( display_label == 0 ) { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("display_load_policy_group args ") + ACE_TEXT ("not provided\n")), + -2); + } + + try + { + + FT_Naming::GroupNames_var list = this->naming_manager_->groups (strategy); + + std::cout << ACE_TEXT ("\n") + << display_label + << ACE_TEXT (" Load Balancing Groups:") + << std::endl; + + if ( list->length () > 0 ) { + + for (unsigned int i = 0; i < list->length (); ++i) + { + std::cout << ACE_TEXT (" ") + << (*list)[i] + << std::endl; + } + + } else { + + std::cout << ACE_TEXT ("No ") + << display_label + << ACE_TEXT (" Load Balancing Groups Registered") + << std::endl; + + } + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ("Exception in group_list"); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Unable to get %C group list\n"), + display_label), + -1); + } + return 0; +} + +/** + * The naming service shall provide a command line utility to modify the load + * balancing strategy for a specified object group. + * Changes the selection algorithm for the specified object group. An object + * group's selection algorithm determines how the naming service directs client + * requests to object group members. + */ +int +NS_group_svc::group_modify ( + const ACE_TCHAR* group_name, + const ACE_TCHAR* policy) +{ + if (group_name == 0 || policy == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("group_modify args not provided\n")), + -2); + } + + try + { + this->naming_manager_->set_load_balancing_strategy ( + ACE_TEXT_ALWAYS_CHAR (group_name), + determine_policy_string(policy) ); + } + catch (const PortableGroup::ObjectGroupNotFound&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to find group %C\n"), + group_name), + -1); + } + catch (const CORBA::Exception&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to modify group %C\n"), + group_name), + -1); + } + + return 0; +} + +/** + * The naming service shall provide a command line utility to remove a specified + * object group from the naming service. + * Removes the specified object group from the naming service. + */ +int +NS_group_svc::group_remove (const ACE_TCHAR* group_name) +{ + if (group_name == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("group_remove args not provided\n")), + -2); + } + + try + { + this->naming_manager_->delete_object_group ( + ACE_TEXT_ALWAYS_CHAR (group_name)); + } + catch (const PortableGroup::ObjectGroupNotFound&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to find group %C\n"), + group_name), + -1); + } + catch (const CORBA::Exception&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to remove group %C\n"), + group_name), + -1); + } + + return 0; +} + +/** + * The naming service shall provide a command line utility for adding object + * references to an object group. + * Adds an object to the specified object group. After being added, the object + * is available for selection. + */ +int +NS_group_svc::member_add ( + const ACE_TCHAR* group_name, + const ACE_TCHAR* location, + const ACE_TCHAR* ior) +{ + if (group_name == 0 || location == 0 || ior == 0 ) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("member_add args not provided\n")), + -2); + } + + try + { + PortableGroup::Location location_name; + location_name.length (1); + location_name[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR (location)); + + PortableGroup::ObjectGroup_var group_var = + this->naming_manager_->get_object_group_ref_from_name ( + ACE_TEXT_ALWAYS_CHAR (group_name)); + + CORBA::Object_var ior_var = + this->orb_->string_to_object(ACE_TEXT_ALWAYS_CHAR (ior)); + + if (CORBA::is_nil (ior_var.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nInvalid member IOR provided.\n")), + -1); + } + + this->naming_manager_->add_member ( + group_var.in(), + location_name, + ior_var.in()); + + } + catch (const PortableGroup::ObjectGroupNotFound&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to find group %C\n"), + group_name), + -1); + } + catch (const PortableGroup::ObjectNotAdded&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to add location %C to group %C\n"), + location, group_name), + -1); + } + catch (const CORBA::Exception&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to add location %C to group %C\n"), + location, group_name), + -1); + } + + return 0; +} + +/** + * The naming service shall provide a command line utility for displaying all + * members (object references) for a specified object group. + * Lists the members of the specified object group. + */ +int +NS_group_svc::member_list (const ACE_TCHAR* group_name) +{ + if (group_name == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("member_list args not provided\n")), + -2); + } + + try + { + PortableGroup::ObjectGroup_var group_var = + this->naming_manager_->get_object_group_ref_from_name ( + ACE_TEXT_ALWAYS_CHAR (group_name)); + + PortableGroup::Locations_var locations = + this->naming_manager_->locations_of_members (group_var.in()); + + for (unsigned int i = 0; i < locations->length(); ++i) + { + const PortableGroup::Location & loc = locations[i]; + if (loc.length() > 0) { + std::cout << loc[0].id.in() << std::endl; + } + } + + } + catch (const PortableGroup::ObjectGroupNotFound&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to find group %C\n"), + group_name), + -1); + } + catch (const CORBA::Exception&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to list members for group %C\n"), + group_name), + -1); + } + + return 0; +} + +/** + * The naming service shall provide a command line utility for removing object + * references from an object group. + * Removes the specified member object from the specified object group. + */ +int +NS_group_svc::member_remove ( + const ACE_TCHAR* group_name, + const ACE_TCHAR* location) +{ + if (group_name == 0 || location == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("member_remove args not provided\n")), + -2); + } + + /** + * Remove an object at a specific location from the given + * ObjectGroup. Deletion of application created objects must be + * deleted by the application. Objects created by the + * infrastructure (load balancer) will be deleted by the + * infrastructure. + */ + + try + { + PortableGroup::Location location_name; + location_name.length (1); + location_name[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR (location)); + + PortableGroup::ObjectGroup_var group_var = + this->naming_manager_->get_object_group_ref_from_name ( + ACE_TEXT_ALWAYS_CHAR (group_name)); + + this->naming_manager_->remove_member ( + group_var.in(), + location_name); + } + catch (const PortableGroup::ObjectGroupNotFound&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to find group %C\n"), + group_name), + -1); + } + catch (const PortableGroup::MemberNotFound&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to find member %C\n"), + location), + -1); + } + catch (const CORBA::Exception&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to remove member %C\n"), + location), + -1); + } + + return 0; +} + +/** + * The naming service shall provide a command line utility to display an object + * reference from a specified object group. + * Displays the object reference that cooresponds to the specified member of an + * object group. + */ +int +NS_group_svc::member_show ( + const ACE_TCHAR* group_name, + const ACE_TCHAR* location) +{ + if (group_name == 0 || location == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("member_show args not provided\n")), + -2); + } + + //Get and display IOR for the member location + try + { + PortableGroup::Location location_name (1); + location_name.length (1); + location_name[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR (location)); + + PortableGroup::ObjectGroup_var group_var = + this->naming_manager_->get_object_group_ref_from_name ( + ACE_TEXT_ALWAYS_CHAR (group_name)); + + CORBA::Object_var ior_var = + this->naming_manager_->get_member_ref (group_var.in(), location_name); + + CORBA::String_var ior_string = + this->orb_->object_to_string (ior_var.in()); + + std::cout << ior_string.in() << std::endl; + } + catch (const PortableGroup::ObjectGroupNotFound&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to find group %C\n"), + group_name), + -1); + } + catch (const PortableGroup::MemberNotFound&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to find member location %C\n"), + location), + -1); + } + catch (const CORBA::Exception&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("\nUnable to show member location %C\n"), + location), + -1); + } + + return 0; +} diff --git a/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/nsgroup_svc.h b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/nsgroup_svc.h new file mode 100644 index 00000000000..6f819780764 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/FaultTolerant/nsgroup_svc.h @@ -0,0 +1,184 @@ +//========================================================================== +/** + * @file nsgroup_svc.h + * + * $Id$ + * + * @author Phillip LaBanca <labancap@ociweb.com> + */ +//========================================================================== + +#ifndef i_nsgroup_svc_h +#define i_nsgroup_svc_h + +#include "orbsvcs/FT_NamingManagerC.h" +#include /**/ "orbsvcs/Naming/FaultTolerant/ftnaming_intf_export.h" + +/** + * @class NS_group_svc + * + * @brief Encapsulate the NS group operations in a class. + * + * + */ +class TAO_FtNaming_Intf_Export NS_group_svc +{ +public: + + /** + * Constructor + */ + NS_group_svc (void); + + /** + * The naming service shall provide a command line utility for creating + * object groups. + * + * @param group group name + * @param policy round | rand | least + * + * @return 0 on success, -1 on failure, -2 on bad argument. + */ + int group_create (const ACE_TCHAR* group, const ACE_TCHAR* policy); + + /** + * The naming service shall provide a command line utility for binding an + * object group to a path in the naming service. + * + * @param group group name + * @param path stringified name in the naming service + * + * @return 0 on success, -1 on failure, -2 on bad argument. + */ + int group_bind (const ACE_TCHAR* group, const ACE_TCHAR* path); + + /** + * @param group group name + * @param path stringified name in the naming service + * + * @return 0 on success, -1 on failure, -2 on bad argument. + */ + int group_unbind (const ACE_TCHAR* path); + + /** + * The naming service shall provide a command line utility to display all + * defined object groups within the naming service. + * + * @return 0 on success, -1 on failure, -2 on bad argument. + */ + int group_list (void); + + /** + * The naming service shall provide a command line utility to modify the load + * balancing strategy for a specified object group. + * + * @param group group name + * @param policy round | rand | least + * + * @return 0 on success, -1 on failure, -2 on bad argument. + */ + int group_modify (const ACE_TCHAR* group, const ACE_TCHAR* policy); + + /** + * The naming service shall provide a command line utility to remove a + * specified object group from the naming service. + * + * @param group group name + * + * @return 0 on success, -1 on failure, -2 on bad argument. + */ + int group_remove (const ACE_TCHAR* group); + + /** + * The naming service shall provide a command line utility for adding object + * references to an object group. + * + * @param group group name + * @param location member location string + * @param ior member stringified ior + * + * @return 0 on success, -1 on failure, -2 on bad argument. + */ + int member_add (const ACE_TCHAR* group, + const ACE_TCHAR* location, + const ACE_TCHAR* ior); + + /** + * The naming service shall provide a command line utility for displaying all + * members (object references) for a specified object group. + * + * @param group group name + * + * @return 0 on success, -1 on failure, -2 on bad argument. + */ + int member_list (const ACE_TCHAR* group); + + /** + * The naming service shall provide a command line utility for removing + * object references from an object group. + * + * @param group group name + * @param location member location string + * + * @return 0 on success, -1 on failure, -2 on bad argument. + */ + int member_remove (const ACE_TCHAR* group, const ACE_TCHAR* location); + + /** + * The naming service shall provide a command line utility to display an + * object reference from a specified object group. + * + * @param group group name + * @param location member location string + * + * @return zero for success; nonzero for failure. + */ + int member_show (const ACE_TCHAR* group, const ACE_TCHAR* location); + + /** + * @param group group name + * + * @return true if the specified object group name is found + */ + bool group_exist (const ACE_TCHAR* group_name); + + /** + * @return 0 on success, -1 on failure. + */ + int set_orb( CORBA::ORB_ptr value); + + /** + * @return 0 on success, -1 on failure. + */ + int set_naming_manager( FT_Naming::NamingManager_ptr value); + + /** + * @return 0 on success, -1 on failure. + */ + int set_name_context( CosNaming::NamingContextExt_ptr value); + +private: + + /** + * determine stategy based on policy string value default to ROUND_ROBIN + * + * @param policy round | rand | least + */ + FT_Naming::LoadBalancingStrategyValue determine_policy_string (const ACE_TCHAR *policy); + + /** + * @return 0 on success, -1 on failure. + */ + int display_load_policy_group( FT_Naming::LoadBalancingStrategyValue strategy, const ACE_TCHAR *display_label); + +private: + + FT_Naming::NamingManager_var naming_manager_; + + CosNaming::NamingContextExt_var name_service_; + + CORBA::ORB_var orb_; + +}; + +#endif diff --git a/TAO/orbsvcs/orbsvcs/Naming/Flat_File_Persistence.cpp b/TAO/orbsvcs/orbsvcs/Naming/Flat_File_Persistence.cpp deleted file mode 100644 index 072951cd015..00000000000 --- a/TAO/orbsvcs/orbsvcs/Naming/Flat_File_Persistence.cpp +++ /dev/null @@ -1,386 +0,0 @@ -// $Id$ - -//----------------------------------------------------------------------------- -// Flat File class implementations -//----------------------------------------------------------------------------- -#include "orbsvcs/Naming/Flat_File_Persistence.h" - -#include "ace/Log_Msg.h" -#include "ace/Numeric_Limits.h" -#include "ace/Auto_Ptr.h" -#include "ace/OS_NS_sys_stat.h" -#include "ace/OS_NS_unistd.h" -#include "ace/OS_NS_fcntl.h" - -TAO_BEGIN_VERSIONED_NAMESPACE_DECL - -TAO_NS_FlatFileStream::TAO_NS_FlatFileStream (const ACE_CString & file, - const char * mode) - : fl_ (0) -{ - ACE_TRACE("TAO_NS_FlatFileStream"); - file_ = file; - mode_ = mode; -} - -TAO_NS_FlatFileStream::~TAO_NS_FlatFileStream () -{ - ACE_TRACE("~TAO_NS_FlatFileStream"); - if ( fl_ != 0 ) - this->close(); -} - -void -TAO_NS_FlatFileStream::remove () -{ - ACE_TRACE("remove"); - ACE_OS::unlink(ACE_TEXT_CHAR_TO_TCHAR(file_.c_str())); -} - -int -TAO_NS_FlatFileStream::exists () -{ - ACE_TRACE("exists"); - // We could check the mode for this file, but for now just check exists - return ! ACE_OS::access(file_.c_str(), F_OK); -} - -int -TAO_NS_FlatFileStream::open() -{ - ACE_TRACE("open"); - // For now, three flags exist "r", "w", and "c" - int flags = 0; - const char *fdmode = 0; - if( ACE_OS::strchr(mode_.c_str(), 'r') ) - if( ACE_OS::strchr(mode_.c_str(), 'w') ) - flags = O_RDWR, fdmode = "r+"; - else - flags = O_RDONLY, fdmode = "r"; - else - flags = O_WRONLY, fdmode = "w"; - if( ACE_OS::strchr(mode_.c_str(), 'c') ) - flags |= O_CREAT; -#ifndef ACE_WIN32 - if( ACE_OS::flock_init (&filelock_, flags, ACE_TEXT_CHAR_TO_TCHAR(file_.c_str()), 0666) != 0 ) - ACE_ERROR_RETURN ((LM_ERROR, - "Cannot open file %s for mode %s: (%d) %s\n", - file_.c_str(), mode_.c_str(), - errno, ACE_OS::strerror(errno)), - -1); -#else - if( (filelock_.handle_= ACE_OS::open (ACE_TEXT_CHAR_TO_TCHAR(file_.c_str()), flags, 0)) == ACE_INVALID_HANDLE ) - ACE_ERROR_RETURN ((LM_ERROR, - "Cannot open file %s for mode %s: (%d) %s\n", - file_.c_str(), mode_.c_str(), - ACE_ERRNO_GET, ACE_OS::strerror(ACE_ERRNO_GET)), - -1); -#endif - this->fl_ = ACE_OS::fdopen(filelock_.handle_, ACE_TEXT_CHAR_TO_TCHAR(fdmode)); - if (this->fl_ == 0) - ACE_ERROR_RETURN ((LM_ERROR, - "Cannot fdopen file %s for mode %s: (%d) %s\n", - file_.c_str(), mode_.c_str(), - ACE_ERRNO_GET, ACE_OS::strerror(ACE_ERRNO_GET)), - -1); - return 0; -} - -int -TAO_NS_FlatFileStream::close() -{ - ACE_TRACE("close"); - ACE_OS::fflush(fl_); -#ifndef ACE_WIN32 - ACE_OS::flock_destroy (&filelock_, 0); -#endif - ACE_OS::fclose (fl_); // even though flock_destroy closes the handle - // we still need to destroy the FILE* - - fl_ = 0; - return 0; -} - -int -TAO_NS_FlatFileStream::flock (int whence, int start, int len) -{ - ACE_TRACE("flock"); -#if defined (ACE_WIN32) - ACE_UNUSED_ARG (whence); - ACE_UNUSED_ARG (start); - ACE_UNUSED_ARG (len); -#else - if( ACE_OS::strcmp(mode_.c_str(), "r") == 0 ) - ACE_OS::flock_rdlock(&filelock_, whence, start, len); - else - ACE_OS::flock_wrlock(&filelock_, whence, start, len); -#endif - return 0; -} - -int -TAO_NS_FlatFileStream::funlock (int whence, int start, int len) -{ - ACE_TRACE("funlock"); -#if defined (ACE_WIN32) - ACE_UNUSED_ARG (whence); - ACE_UNUSED_ARG (start); - ACE_UNUSED_ARG (len); -#else - ACE_OS::flock_unlock(&filelock_, whence, start, len); -#endif - return 0; -} - -time_t -TAO_NS_FlatFileStream::last_changed(void) -{ - ACE_TRACE("TAO_NS_FlatFileStream::last_changed"); - ACE_stat st; - ACE_OS::fstat(filelock_.handle_, &st); - return st.st_mtime; -} - -TAO_Storable_Base & -TAO_NS_FlatFileStream::operator <<( - const TAO_NS_Persistence_Header &header) -{ - ACE_TRACE("TAO_NS_FlatFileStream::operator <<"); - ACE_OS::rewind(this->fl_); - ACE_OS::fprintf(this->fl_, "%d\n%d\n", header.size(), header.destroyed()); - ACE_OS::fflush(this->fl_); - - return *this; -} - -TAO_Storable_Base & -TAO_NS_FlatFileStream::operator >>( - TAO_NS_Persistence_Header &header) -{ - ACE_TRACE("TAO_NS_FlatFileStream::operator >>"); - unsigned int size; - int destroyed; - - ACE_OS::rewind(this->fl_); - switch (fscanf(fl_, "%u\n", &size)) - { - case 0: - this->setstate (badbit); - return *this; - case EOF: - this->setstate (eofbit); - return *this; - } - header.size(size); - - switch (fscanf(fl_, "%d\n", &destroyed)) - { - case 0: - this->setstate (badbit); - return *this; - case EOF: - this->setstate (eofbit); - return *this; - } - header.destroyed(destroyed); - - return *this; - -} - -TAO_Storable_Base & -TAO_NS_FlatFileStream::operator <<( - const TAO_NS_Persistence_Record &record) -{ - ACE_TRACE("TAO_NS_FlatFileStream::operator <<"); - TAO_NS_Persistence_Record::Record_Type type = record.type(); - ACE_OS::fprintf(this->fl_, "%d\n", type); - - ACE_CString id = record.id(); - ACE_OS::fprintf(this->fl_, ACE_SIZE_T_FORMAT_SPECIFIER ACE_TEXT("\n%s\n"), - id.length(), id.c_str()); - - ACE_CString kind = record.kind(); - ACE_OS::fprintf(this->fl_, ACE_SIZE_T_FORMAT_SPECIFIER ACE_TEXT ("\n%s\n"), - kind.length(), kind.c_str()); - - ACE_CString ref = record.ref(); - ACE_OS::fprintf(this->fl_, ACE_SIZE_T_FORMAT_SPECIFIER ACE_TEXT ("\n%s\n"), - ref.length(), ref.c_str()); - - ACE_OS::fflush(this->fl_); - - return *this; -} - -TAO_Storable_Base & -TAO_NS_FlatFileStream::operator >>(TAO_NS_Persistence_Record &record) -{ - ACE_TRACE("TAO_NS_FlatFileStream::operator >>"); - - int temp_type_in; - switch (fscanf(fl_, "%d\n", &temp_type_in)) - { - case 0: - this->setstate (badbit); - return *this; - case EOF: - this->setstate (eofbit); - return *this; - } - TAO_NS_Persistence_Record::Record_Type type = - (TAO_NS_Persistence_Record::Record_Type) temp_type_in; - record.type (type); - - int bufSize = 0; - ACE_CString::size_type const max_buf_len = - ACE_Numeric_Limits<ACE_CString::size_type>::max (); - - //id - switch (fscanf(fl_, "%d\n", &bufSize)) - { - case 0: - this->setstate (badbit); - return *this; - case EOF: - this->setstate (eofbit); - return *this; - } - - if (bufSize < 0 - || static_cast<ACE_CString::size_type> (bufSize) >= max_buf_len) - { - this->setstate (badbit); - return *this; - } - { - ACE_Auto_Basic_Array_Ptr<char> the_id (new char[bufSize + 1]); - the_id[0] = '\0'; - if (ACE_OS::fgets (ACE_TEXT_CHAR_TO_TCHAR (the_id.get ()), - bufSize + 1, - fl_) == 0 - && bufSize != 0) - { - this->setstate (badbit); - return *this; - } - record.id (ACE_CString (the_id.get (), 0, false)); - } - - //kind - switch (fscanf(fl_, "%d\n", &bufSize)) - { - case 0: - this->setstate (badbit); - return *this; - case EOF: - this->setstate (eofbit); - return *this; - } - - if (bufSize < 0 - || static_cast<ACE_CString::size_type> (bufSize) >= max_buf_len) - { - this->setstate (badbit); - return *this; - } - - { - ACE_Auto_Basic_Array_Ptr<char> the_kind (new char[bufSize + 1]); - the_kind[0] = '\0'; - if (ACE_OS::fgets (ACE_TEXT_CHAR_TO_TCHAR (the_kind.get ()), - bufSize + 1, - fl_) == 0 - && bufSize != 0) - { - this->setstate (badbit); - return *this; - } - record.kind (ACE_CString (the_kind.get (), 0, false)); - } - - //ref - switch (fscanf(fl_, "%d\n", &bufSize)) - { - case 0: - this->setstate (badbit); - return *this; - case EOF: - this->setstate (eofbit); - return *this; - } - - if (bufSize < 0 - || static_cast<ACE_CString::size_type> (bufSize) >= max_buf_len) - { - this->setstate (badbit); - return *this; - } - - { - ACE_Auto_Basic_Array_Ptr<char> the_ref (new char[bufSize + 1]); - the_ref[0] = '\0'; - if (ACE_OS::fgets (ACE_TEXT_CHAR_TO_TCHAR (the_ref.get ()), - bufSize + 1, - fl_) == 0 - && bufSize != 0) - { - this->setstate (badbit); - return *this; - } - record.ref (ACE_CString (the_ref.get (), 0, false)); - } - - return *this; - -} - -TAO_Storable_Base & -TAO_NS_FlatFileStream::operator <<( - const TAO_NS_Persistence_Global &global) -{ - ACE_TRACE("TAO_NS_FlatFileStream::operator <<"); - ACE_OS::rewind(this->fl_); - ACE_OS::fprintf(this->fl_, "%d\n", global.counter()); - ACE_OS::fflush(this->fl_); - - return *this; -} - -TAO_Storable_Base & -TAO_NS_FlatFileStream::operator >>( - TAO_NS_Persistence_Global &global) -{ - ACE_TRACE("TAO_NS_FlatFileStream::operator >>"); - unsigned int counter = 0; - - ACE_OS::rewind(this->fl_); - switch (fscanf(fl_, "%u\n", &counter)) - { - case 0: - this->setstate (badbit); - break; // Still set the global.counter (to 0) - case EOF: - this->setstate (eofbit); - break; // Still set the global.counter (to 0) - } - global.counter(counter); - - return *this; -} - - -TAO_Storable_Base * -TAO_NS_FlatFileFactory::create_stream (const ACE_CString & file, - const ACE_TCHAR * mode) -{ - ACE_TRACE("TAO_NS_FlatFileFactory::create_stream"); - TAO_Storable_Base *stream = 0; - - ACE_NEW_RETURN (stream, - TAO_NS_FlatFileStream(file, ACE_TEXT_ALWAYS_CHAR (mode)), - 0); - return stream; -} - -TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/Flat_File_Persistence.h b/TAO/orbsvcs/orbsvcs/Naming/Flat_File_Persistence.h deleted file mode 100644 index 7b03ba75b03..00000000000 --- a/TAO/orbsvcs/orbsvcs/Naming/Flat_File_Persistence.h +++ /dev/null @@ -1,95 +0,0 @@ -// -*- C++ -*- - -//============================================================================= -/** - * @file Flat_File_Persistence.h - * - * $Id$ - * - * @author Marina Spivak <marina@cs.wustl.edu> - */ -//============================================================================= - -#ifndef TAO_FLAT_FILE_PERSISTENCE_H -#define TAO_FLAT_FILE_PERSISTENCE_H - -#include "orbsvcs/Naming/Storable.h" -#include "ace/OS_NS_stdio.h" - -TAO_BEGIN_VERSIONED_NAMESPACE_DECL - -//------------------------------------------------------------------------ -// The Flat File concrete classes -//------------------------------------------------------------------------ -class TAO_NS_FlatFileStream : public TAO_Storable_Base -{ -public: - - TAO_NS_FlatFileStream(const ACE_CString & file, const char * mode); - virtual ~TAO_NS_FlatFileStream(); - - /// Remove a file by name (file is not open) - virtual void remove(); - - /// Check if a file exists on disk (file is not open) - virtual int exists(); - - /// Open a file (the remaining methods below all require an open file) - virtual int open(); - - /// Close an open file - virtual int close(); - - /// Acquire a file lock - virtual int flock (int whence, int start, int len); - - /// Release a file lock - virtual int funlock (int whence, int start, int len); - - /// Returns the last time an open file was changed - virtual time_t last_changed(void); - - /// Write a header to disk - virtual TAO_Storable_Base& operator << ( - const TAO_NS_Persistence_Header& header); - - /// Read a header from disk - virtual TAO_Storable_Base& operator >> ( - TAO_NS_Persistence_Header& header); - - /// Write a record to disk - virtual TAO_Storable_Base& operator << ( - const TAO_NS_Persistence_Record& record); - - /// Read a record from disk - virtual TAO_Storable_Base& operator >> ( - TAO_NS_Persistence_Record& record); - - /// Write the global data to disk - virtual TAO_Storable_Base& operator << ( - const TAO_NS_Persistence_Global& global); - - /// Read the global data from disk - virtual TAO_Storable_Base& operator >> ( - TAO_NS_Persistence_Global& global); - -private: - ACE_OS::ace_flock_t filelock_; - FILE* fl_; - ACE_CString file_; - ACE_CString mode_; -}; - -class TAO_NS_FlatFileFactory : public TAO_Naming_Service_Persistence_Factory -{ -public: - // Factory Methods - - /// Create the stream that can operate on a disk file - virtual TAO_Storable_Base *create_stream(const ACE_CString & file, - const ACE_TCHAR * mode); -}; - -TAO_END_VERSIONED_NAMESPACE_DECL - -#endif diff --git a/TAO/orbsvcs/orbsvcs/Naming/Hash_Naming_Context.cpp b/TAO/orbsvcs/orbsvcs/Naming/Hash_Naming_Context.cpp index f3b6182e33e..de3c6d1c4f5 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Hash_Naming_Context.cpp +++ b/TAO/orbsvcs/orbsvcs/Naming/Hash_Naming_Context.cpp @@ -97,10 +97,6 @@ TAO_Hash_Naming_Context::get_context (const CosNaming::Name &name) void TAO_Hash_Naming_Context::bind (const CosNaming::Name& n, CORBA::Object_ptr obj) { - ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, - ace_mon, this->lock_, - CORBA::INTERNAL ()); - // Check to make sure this object didn't have <destroy> method // invoked on it. if (this->destroyed_) @@ -136,6 +132,10 @@ TAO_Hash_Naming_Context::bind (const CosNaming::Name& n, CORBA::Object_ptr obj) // If we received a simple name, we need to bind it in this context. else { + ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, + ace_mon, this->lock_, + CORBA::INTERNAL ()); + // Try binding the name. int result = this->context_->bind (n[0].id, n[0].kind, @@ -154,10 +154,6 @@ void TAO_Hash_Naming_Context::rebind (const CosNaming::Name& n, CORBA::Object_ptr obj) { - ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, - this->lock_, - CORBA::INTERNAL ()); - // Check to make sure this object didn't have <destroy> method // invoked on it. if (this->destroyed_) @@ -194,6 +190,10 @@ TAO_Hash_Naming_Context::rebind (const CosNaming::Name& n, // If we received a simple name, we need to rebind it in this // context. { + ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, + this->lock_, + CORBA::INTERNAL ()); + int result = this->context_->rebind (n[0].id, n[0].kind, obj, @@ -212,10 +212,6 @@ void TAO_Hash_Naming_Context::bind_context (const CosNaming::Name &n, CosNaming::NamingContext_ptr nc) { - ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, - this->lock_, - CORBA::INTERNAL ()); - // Check to make sure this object didn't have <destroy> method // invoked on it. if (this->destroyed_) @@ -255,6 +251,10 @@ TAO_Hash_Naming_Context::bind_context (const CosNaming::Name &n, // If we received a simple name, we need to bind it in this context. else { + ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, + this->lock_, + CORBA::INTERNAL ()); + // Try binding the name. int result = this->context_->bind (n[0].id, n[0].kind, @@ -273,10 +273,6 @@ void TAO_Hash_Naming_Context::rebind_context (const CosNaming::Name &n, CosNaming::NamingContext_ptr nc) { - ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, - this->lock_, - CORBA::INTERNAL ()); - // Check to make sure this object didn't have <destroy> method // invoked on it. if (this->destroyed_) @@ -314,6 +310,10 @@ TAO_Hash_Naming_Context::rebind_context (const CosNaming::Name &n, // If we received a simple name, we need to rebind it in this // context. { + ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, + this->lock_, + CORBA::INTERNAL ()); + int result = this->context_->rebind (n[0].id, n[0].kind, nc, @@ -332,9 +332,6 @@ TAO_Hash_Naming_Context::rebind_context (const CosNaming::Name &n, CORBA::Object_ptr TAO_Hash_Naming_Context::resolve (const CosNaming::Name& n) { - ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, - CORBA::INTERNAL ()); - // Check to make sure this object didn't have <destroy> method // invoked on it. if (this->destroyed_) @@ -355,14 +352,16 @@ TAO_Hash_Naming_Context::resolve (const CosNaming::Name& n) // Stores the object reference bound to the first name component. CORBA::Object_var result; - if (this->context_->find (n[0].id, - n[0].kind, - result.out (), - type) == -1) - throw CosNaming::NamingContext::NotFound( - CosNaming::NamingContext::missing_node, - n); - + { + ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, + CORBA::INTERNAL ()); + if (this->context_->find (n[0].id, + n[0].kind, + result.out (), + type) == -1) + throw CosNaming::NamingContext::NotFound + (CosNaming::NamingContext::missing_node, n); + } // If the name we have to resolve is a compound name, we need to // resolve it recursively. if (name_len > 1) @@ -410,11 +409,25 @@ TAO_Hash_Naming_Context::resolve (const CosNaming::Name& n) } catch (const CORBA::SystemException&) { - throw CosNaming::NamingContext::CannotProceed( - context.in (), rest_of_name); + throw CosNaming::NamingContext::CannotProceed + (context.in (), rest_of_name); } } } + else + { + ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, + this->lock_, + CORBA::INTERNAL ()); + + if (this->context_->find (n[0].id, + n[0].kind, + result.out (), + type) == -1) + throw CosNaming::NamingContext::NotFound + (CosNaming::NamingContext::missing_node, n); + } + // If the name we had to resolve was simple, we just need to return // the result. return result._retn (); @@ -423,10 +436,6 @@ TAO_Hash_Naming_Context::resolve (const CosNaming::Name& n) void TAO_Hash_Naming_Context::unbind (const CosNaming::Name& n) { - ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, - this->lock_, - CORBA::INTERNAL ()); - // Check to make sure this object didn't have <destroy> method // invoked on it. if (this->destroyed_) @@ -463,20 +472,21 @@ TAO_Hash_Naming_Context::unbind (const CosNaming::Name& n) // If we received a simple name, we need to unbind it in this // context. else - if (this->context_->unbind (n[0].id, - n[0].kind) == -1) - throw CosNaming::NamingContext::NotFound( - CosNaming::NamingContext::missing_node, n); + { + ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, ace_mon, + this->lock_, + CORBA::INTERNAL ()); + + if (this->context_->unbind (n[0].id, + n[0].kind) == -1) + throw CosNaming::NamingContext::NotFound + (CosNaming::NamingContext::missing_node, n); + } } CosNaming::NamingContext_ptr TAO_Hash_Naming_Context::bind_new_context (const CosNaming::Name& n) { - ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, - ace_mon, - this->lock_, - CORBA::INTERNAL ()); - // Check to make sure this object didn't have <destroy> method // invoked on it. if (this->destroyed_) @@ -506,16 +516,15 @@ TAO_Hash_Naming_Context::bind_new_context (const CosNaming::Name& n) // If we received a simple name, we need to bind it in this context. // Stores our new Naming Context. - CosNaming::NamingContext_var result = - CosNaming::NamingContext::_nil (); + CosNaming::NamingContext_var result = CosNaming::NamingContext::_nil (); // Create new context. - result = new_context (); + result = this->new_context (); // Bind the new context to the name. try { - bind_context (n, result.in ()); + this->bind_context (n, result.in ()); } catch (const CORBA::Exception&) { @@ -540,11 +549,6 @@ TAO_Hash_Naming_Context::bind_new_context (const CosNaming::Name& n) void TAO_Hash_Naming_Context::destroy (void) { - ACE_GUARD_THROW_EX (TAO_SYNCH_RECURSIVE_MUTEX, - ace_mon, - this->lock_, - CORBA::INTERNAL ()); - // Check to make sure this object didn't have <destroy> method // invoked on it. if (this->destroyed_) diff --git a/TAO/orbsvcs/orbsvcs/Naming/Naming_Context_Interface.cpp b/TAO/orbsvcs/orbsvcs/Naming/Naming_Context_Interface.cpp index df5cb7b77e7..675ce30a086 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Naming_Context_Interface.cpp +++ b/TAO/orbsvcs/orbsvcs/Naming/Naming_Context_Interface.cpp @@ -461,8 +461,28 @@ TAO_Naming_Context::resolve_str (const char * n) return this->resolve (name.in ()); } +void +TAO_Naming_Context::stale (bool value) +{ + this->impl_->stale (value); +} + TAO_Naming_Context_Impl::~TAO_Naming_Context_Impl (void) { } +void +TAO_Naming_Context_Impl::stale (bool value) +{ + ACE_UNUSED_ARG (value); + // Default implementation is no-op +} + +bool +TAO_Naming_Context_Impl::stale (void) +{ + // Default implementation is to reply false + return false; +} + TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/Naming_Context_Interface.h b/TAO/orbsvcs/orbsvcs/Naming/Naming_Context_Interface.h index 27d907e5f36..8a0fb32be8e 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Naming_Context_Interface.h +++ b/TAO/orbsvcs/orbsvcs/Naming/Naming_Context_Interface.h @@ -177,6 +177,12 @@ public: */ virtual CORBA::Object_ptr resolve_str (const char * n); + /** + * Mark the implementation stale state for replicated + * persistence support. + */ + void stale (bool value); + /// Returns the Default POA of this Servant object virtual PortableServer::POA_ptr _default_POA (void); @@ -339,6 +345,18 @@ public: /// Returns the Default POA of this Servant object virtual PortableServer::POA_ptr _default_POA (void) = 0; + + /** + * Set the stale flag for replicated persistence support. + */ + virtual void stale (bool value); + + /** + * Query if the the implementation is stale for replicated + * persistence support. + */ + virtual bool stale (void); + }; TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/Naming_Loader.cpp b/TAO/orbsvcs/orbsvcs/Naming/Naming_Loader.cpp index 44736086700..72b836a1c9f 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Naming_Loader.cpp +++ b/TAO/orbsvcs/orbsvcs/Naming/Naming_Loader.cpp @@ -17,19 +17,25 @@ #include "ace/Dynamic_Service.h" #include "ace/Argv_Type_Converter.h" - - +#include "orbsvcs/Naming/Naming_Server.h" TAO_BEGIN_VERSIONED_NAMESPACE_DECL -TAO_Naming_Loader::TAO_Naming_Loader (void) +TAO_Naming_Loader::TAO_Naming_Loader (TAO_Naming_Server *server) +: naming_server_(server) { // Constructor + + // If no server was provided, then we will construct one of the + // base class type. + if (naming_server_ == 0) + ACE_NEW (naming_server_, TAO_Naming_Server); } TAO_Naming_Loader::~TAO_Naming_Loader (void) { - // Destructor + // Destroy the naming server that was created + delete naming_server_; } int @@ -63,7 +69,7 @@ int TAO_Naming_Loader::fini (void) { // Remove the Naming Service. - return this->naming_server_.fini (); + return this->naming_server_->fini (); } CORBA::Object_ptr @@ -71,10 +77,20 @@ TAO_Naming_Loader::create_object (CORBA::ORB_ptr orb, int argc, ACE_TCHAR *argv[]) { - // Initializes the Naming Service. Returns -1 - // on an error. - if (this->naming_server_.init_with_orb (argc, argv, orb) == -1) - return CORBA::Object::_nil (); + + if (this->naming_server_ == 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("TAO_Naming_Loader::create_object - naming_server_ ") + ACE_TEXT ("never set.\n"))); + } + else + { + // Initializes the Naming Service. Returns -1 + // on an error. + if (this->naming_server_->init_with_orb (argc, argv, orb) == -1) + return CORBA::Object::_nil (); + } return CORBA::Object::_nil (); } diff --git a/TAO/orbsvcs/orbsvcs/Naming/Naming_Loader.h b/TAO/orbsvcs/orbsvcs/Naming/Naming_Loader.h index 7365fa103e7..c5bb1016bee 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Naming_Loader.h +++ b/TAO/orbsvcs/orbsvcs/Naming/Naming_Loader.h @@ -33,7 +33,10 @@ class TAO_Naming_Serv_Export TAO_Naming_Loader : public TAO_Object_Loader public: /// Constructor - TAO_Naming_Loader (void); + /// By default will use the standard Naming_Server. If a server is provided + /// it will use that one instead. This object takes ownership of the provided + /// Naming Server. + TAO_Naming_Loader (TAO_Naming_Server *server = 0); /// Destructor ~TAO_Naming_Loader (void); @@ -53,8 +56,9 @@ public: ACE_TCHAR *argv[]); protected: + /// TODO: Need to set up service configurator to initialize the naming server /// Instance of the TAO_Naming_Server - TAO_Naming_Server naming_server_; + TAO_Naming_Server* naming_server_; private: TAO_Naming_Loader (const TAO_Naming_Loader &); diff --git a/TAO/orbsvcs/orbsvcs/Naming/Naming_Server.cpp b/TAO/orbsvcs/orbsvcs/Naming/Naming_Server.cpp index 1a021f655ff..9aa2073f9b6 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Naming_Server.cpp +++ b/TAO/orbsvcs/orbsvcs/Naming/Naming_Server.cpp @@ -2,12 +2,17 @@ #include "orbsvcs/Naming/Naming_Server.h" #include "orbsvcs/Naming/Transient_Naming_Context.h" +#include "orbsvcs/Naming/Persistent_Naming_Context_Factory.h" +#include "orbsvcs/Naming/Storable_Naming_Context_Factory.h" + #if !defined (CORBA_E_MICRO) #include "orbsvcs/Naming/Persistent_Context_Index.h" #include "orbsvcs/Naming/Storable_Naming_Context.h" #include "orbsvcs/Naming/Storable_Naming_Context_Activator.h" -#include "orbsvcs/Naming/Flat_File_Persistence.h" + +#include "tao/Storable_FlatFileStream.h" + #endif /* CORBA_E_MICRO */ #include "orbsvcs/CosNamingC.h" @@ -269,6 +274,7 @@ TAO_Naming_Server::parse_args (int argc, ACE_TEXT ("-p <pid_file_name> ") ACE_TEXT ("-s <context_size> ") ACE_TEXT ("-b <base_address> ") + ACE_TEXT ("-u <persistence dir name> ") ACE_TEXT ("-m <1=enable multicast, 0=disable multicast(default) ") ACE_TEXT ("%s") ACE_TEXT ("-z <relative round trip timeout> ") @@ -419,10 +425,12 @@ TAO_Naming_Server::init_with_orb (int argc, return -1; } + // If an ior file name was provided on command line if (this->ior_file_name_ != 0) { - FILE *iorf = ACE_OS::fopen (this->ior_file_name_, ACE_TEXT("w")); - if (iorf == 0) + CORBA::String_var ns_ior = this->naming_service_ior (); + if (this->write_ior_to_file (ns_ior.in (), + this->ior_file_name_) != 0) { ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT("Unable to open %s for writing:(%u) %p\n"), @@ -431,11 +439,6 @@ TAO_Naming_Server::init_with_orb (int argc, ACE_TEXT("TAO_Naming_Server::init_with_orb")), -1); } - - CORBA::String_var str = this->naming_service_ior (); - - ACE_OS::fprintf (iorf, "%s\n", str.in ()); - ACE_OS::fclose (iorf); } if (this->pid_file_name_ != 0) @@ -476,9 +479,18 @@ TAO_Naming_Server::init_new_naming (CORBA::ORB_ptr orb, // In lieu of a fully implemented service configurator version // of this Reader and Writer, let's just take something off the // command line for now. - TAO_Naming_Service_Persistence_Factory* pf = 0; - ACE_NEW_RETURN(pf, TAO_NS_FlatFileFactory, -1); - auto_ptr<TAO_Naming_Service_Persistence_Factory> persFactory(pf); + TAO::Storable_Factory* pf = 0; + ACE_NEW_RETURN (pf, TAO::Storable_FlatFileFactory(persistence_location), -1); + auto_ptr<TAO::Storable_Factory> persFactory(pf); + + // Use an auto_ptr to ensure that we clean up the factory in the case + // of a failure in creating and registering the Activator. + TAO_Storable_Naming_Context_Factory* cf = + this->storable_naming_context_factory (context_size); + // Make sure we got a factory + if (cf == 0) return -1; + auto_ptr<TAO_Storable_Naming_Context_Factory> contextFactory (cf); + // This instance will either get deleted after recreate all or, // in the case of a servant activator's use, on destruction of the // activator. @@ -487,7 +499,7 @@ TAO_Naming_Server::init_new_naming (CORBA::ORB_ptr orb, if (persistence_location == 0) { // No, assign the default location "NameService" - persistence_location = ACE_TEXT("NameService"); + persistence_location = ACE_TEXT ("NameService"); } // Now make sure this directory exists @@ -502,34 +514,70 @@ TAO_Naming_Server::init_new_naming (CORBA::ORB_ptr orb, ACE_NEW_THROW_EX (this->servant_activator_, TAO_Storable_Naming_Context_Activator (orb, persFactory.get(), - persistence_location, - context_size), + contextFactory.get (), + persistence_location), CORBA::NO_MEMORY ()); this->ns_poa_->set_servant_manager(this->servant_activator_); } #endif /* TAO_HAS_MINIMUM_POA */ + try { // The following might throw an exception. + this->naming_context_ = + TAO_Storable_Naming_Context::recreate_all (orb, + poa, + TAO_ROOT_NAMING_CONTEXT, + context_size, + 0, + contextFactory.get (), + persFactory.get (), + use_redundancy_); + } + catch (const CORBA::Exception& ex) + { + // The activator already took over the factories so we need to release the auto_ptr + if (this->use_servant_activator_) + { + // The context factory is now owned by the activator + // so we should release it + contextFactory.release (); + // If using a servant activator, the activator now owns the + // factory, so we should release it + persFactory.release (); + } + // Print out the exception and return failure + ex._tao_print_exception ( + "TAO_Naming_Server::init_new_naming"); + return -1; + } + + // Kind of a duplicate of the above here, but we must also release the + // factory autoptrs in the good case as well. + if (this->use_servant_activator_) + { + // The context factory is now owned by the activator + // so we should release it + contextFactory.release (); + // If using a servant activator, the activator now owns the + // factory, so we should release it + persFactory.release (); + } - this->naming_context_ = - TAO_Storable_Naming_Context::recreate_all (orb, - poa, - TAO_ROOT_NAMING_CONTEXT, - context_size, - 0, - persFactory.get(), - persistence_location, - use_redundancy_); - - if (this->use_servant_activator_) - persFactory.release(); - } + } else if (persistence_location != 0) // // Initialize Persistent Naming Service. // { + + // Create Naming Context Implementation Factory to be used for the creation of + // naming contexts by the TAO_Persistent_Context_Index + TAO_Persistent_Naming_Context_Factory *naming_context_factory = + this->persistent_naming_context_factory (); + // Make sure we got a factory. + if (naming_context_factory == 0) return -1; + // Allocate and initialize Persistent Context Index. ACE_NEW_RETURN (this->context_index_, - TAO_Persistent_Context_Index (orb, poa), + TAO_Persistent_Context_Index (orb, poa, naming_context_factory), -1); if (this->context_index_->open (persistence_location, @@ -706,6 +754,51 @@ TAO_Naming_Server::init_new_naming (CORBA::ORB_ptr orb, } int +TAO_Naming_Server::write_ior_to_file (const char* ior_string, + const char* file_name) +{ + if ((file_name != 0) && + (ior_string != 0)) + { + FILE *iorf = ACE_OS::fopen (file_name, ACE_TEXT("w")); + if (iorf == 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("Unable to open %s for writing:(%u) %p\n"), + file_name, + ACE_ERRNO_GET, + ACE_TEXT("Naming_Server::write_ior_to_file")), + -1); + } + + ACE_OS::fprintf (iorf, "%s\n", ior_string); + ACE_OS::fclose (iorf); + } + else + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Invalid file name or IOR string provided") + ACE_TEXT ("to TAO_Naming_Server::write_ior_to_file\n")), + -1); + + } + + return 0; +} + +TAO_Storable_Naming_Context_Factory * +TAO_Naming_Server::storable_naming_context_factory (size_t context_size) +{ + return new (ACE_nothrow) TAO_Storable_Naming_Context_Factory (context_size); +} + +TAO_Persistent_Naming_Context_Factory * +TAO_Naming_Server::persistent_naming_context_factory (void) +{ + return new (ACE_nothrow) TAO_Persistent_Naming_Context_Factory; +} + +int TAO_Naming_Server::fini (void) { // First get rid of the multi cast handler @@ -773,12 +866,17 @@ TAO_Naming_Server::operator-> (void) const return this->naming_context_.ptr (); } + TAO_Naming_Server::~TAO_Naming_Server (void) { #if (TAO_HAS_MINIMUM_POA == 0) && \ !defined (CORBA_E_COMPACT) && !defined (CORBA_E_MICRO) - if (this->use_servant_activator_) - delete this->servant_activator_; + if (this->use_servant_activator_ && + this->servant_activator_) + { + // Activator is reference counted. Don't delete it directly. + this->servant_activator_->_remove_ref (); + } #endif /* TAO_HAS_MINIMUM_POA */ } diff --git a/TAO/orbsvcs/orbsvcs/Naming/Naming_Server.h b/TAO/orbsvcs/orbsvcs/Naming/Naming_Server.h index dd609ec461a..4d970da3706 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Naming_Server.h +++ b/TAO/orbsvcs/orbsvcs/Naming/Naming_Server.h @@ -34,6 +34,9 @@ class TAO_Persistent_Context_Index; class TAO_Storable_Naming_Context_Activator; #endif /* !CORBA_E_MICRO */ +class TAO_Storable_Naming_Context_Factory; +class TAO_Persistent_Naming_Context_Factory; + /** * @class TAO_Naming_Server * @@ -121,13 +124,13 @@ public: /// Initialize the Naming Service with the command line arguments and /// the ORB. - int init_with_orb (int argc, ACE_TCHAR *argv [], CORBA::ORB_ptr orb); + virtual int init_with_orb (int argc, ACE_TCHAR *argv [], CORBA::ORB_ptr orb); /// Destroy the child POA created in @c init_with_orb - int fini (void); + virtual int fini (void); /// Destructor. - ~TAO_Naming_Server (void); + virtual ~TAO_Naming_Server (void); /// Returns the IOR of the naming service. char * naming_service_ior (void); @@ -137,7 +140,8 @@ public: protected: /** - * Helper method: create Naming Service locally. + * Helper method: create Naming Service locally. Can be specialized to + * refine how Naming Service components are created and initialized * Make the root context of size * <context_size>, register it under the <root_poa>, and make the Naming * Service persistent if <persistence_location> is not 0. @@ -146,7 +150,7 @@ protected: * If <enable_multicast> is not zero then the service will respond * to multicast location queries. */ - int init_new_naming (CORBA::ORB_ptr orb, + virtual int init_new_naming (CORBA::ORB_ptr orb, PortableServer::POA_ptr root_poa, const ACE_TCHAR *persistence_location, void *base_addr, @@ -157,7 +161,23 @@ protected: int use_round_trip_timeout = 0); /// parses the arguments. - int parse_args (int argc, ACE_TCHAR *argv[]); + virtual int parse_args (int argc, ACE_TCHAR *argv[]); + + /// Write the provided ior_string to the file. Return 0 if success. + int write_ior_to_file (const char* ior_string, + const char* file_name); + + /* Factory method to create a naming context factory for use with + * the -u and -r options. + */ + virtual TAO_Storable_Naming_Context_Factory * + storable_naming_context_factory (size_t context_size); + + /* Factory method to create a naming context factory for use with + * the -f option. + */ + virtual TAO_Persistent_Naming_Context_Factory * + persistent_naming_context_factory (void); /// Root NamingContext_ptr. CosNaming::NamingContext_var naming_context_; @@ -233,6 +253,7 @@ protected: /// If not zero use round trip timeout policy set to value specified int round_trip_timeout_; int use_round_trip_timeout_; + }; TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/Persistent_Context_Index.cpp b/TAO/orbsvcs/orbsvcs/Naming/Persistent_Context_Index.cpp index 34b74c6b5de..5da2864d20e 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Persistent_Context_Index.cpp +++ b/TAO/orbsvcs/orbsvcs/Naming/Persistent_Context_Index.cpp @@ -2,6 +2,7 @@ #include "orbsvcs/Naming/Persistent_Context_Index.h" #include "orbsvcs/Naming/Persistent_Naming_Context.h" +#include "orbsvcs/Naming/Persistent_Naming_Context_Factory.h" #include "tao/debug.h" @@ -80,19 +81,22 @@ TAO_Persistent_Context_Index::bind (const char *poa_id, TAO_Persistent_Context_Index::TAO_Persistent_Context_Index (CORBA::ORB_ptr orb, - PortableServer::POA_ptr poa) + PortableServer::POA_ptr poa, + TAO_Persistent_Naming_Context_Factory * context_impl_factory) : allocator_ (0), index_ (0), index_file_ (0), base_address_ (0), orb_ (CORBA::ORB::_duplicate (orb)), - poa_ (PortableServer::POA::_duplicate (poa)) + poa_ (PortableServer::POA::_duplicate (poa)), + context_impl_factory_ (context_impl_factory) { } TAO_Persistent_Context_Index::~TAO_Persistent_Context_Index (void) { delete allocator_; + delete context_impl_factory_; ACE_OS::free (reinterpret_cast<void *> (const_cast<ACE_TCHAR *> (index_file_))); } @@ -181,17 +185,14 @@ TAO_Persistent_Context_Index::recreate_all (void) { index_iter->next (entry); - // Put together a servant for the new Naming Context. - - TAO_Persistent_Naming_Context *context_impl = 0; - ACE_NEW_RETURN (context_impl, - TAO_Persistent_Naming_Context (poa_.in (), - entry->ext_id_.poa_id_, - this, - entry->int_id_.hash_map_, - entry->int_id_.counter_), - -1); - + // Put together a servant for the new Naming Context + // Using the naming context factory to create a naming context of the appropriate type + TAO_Persistent_Naming_Context *context_impl = + this->context_impl_factory_->create_naming_context_impl (poa_.in (), + entry->ext_id_.poa_id_, + this, + entry->int_id_.hash_map_, + entry->int_id_.counter_); // Put <context_impl> into the auto pointer temporarily, in case next // allocation fails. @@ -228,6 +229,16 @@ TAO_Persistent_Context_Index::recreate_all (void) return 0; } +TAO_Persistent_Naming_Context* +TAO_Persistent_Context_Index::create_naming_context_impl ( + PortableServer::POA_ptr poa, + const char *poa_id) +{ + return this->context_impl_factory_->create_naming_context_impl(poa, + poa_id, + this); +} + int TAO_Persistent_Context_Index::create_index (void) { diff --git a/TAO/orbsvcs/orbsvcs/Naming/Persistent_Context_Index.h b/TAO/orbsvcs/orbsvcs/Naming/Persistent_Context_Index.h index fe807eae71b..9b7f0a26010 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Persistent_Context_Index.h +++ b/TAO/orbsvcs/orbsvcs/Naming/Persistent_Context_Index.h @@ -23,6 +23,9 @@ #include "ace/Malloc_T.h" #include "ace/MMAP_Memory_Pool.h" +class TAO_Persistent_Naming_Context; +class TAO_Persistent_Naming_Context_Factory; + TAO_BEGIN_VERSIONED_NAMESPACE_DECL /** @@ -64,8 +67,10 @@ public: // = Initialization and termination methods. /// Constructor. - TAO_Persistent_Context_Index (CORBA::ORB_ptr orb, - PortableServer::POA_ptr poa); + TAO_Persistent_Context_Index ( + CORBA::ORB_ptr orb, + PortableServer::POA_ptr poa, + TAO_Persistent_Naming_Context_Factory *context_impl_factory); /** * Create ACE_Allocator, open/create memory-mapped file with the @@ -86,6 +91,15 @@ public: int init (size_t context_size); /** + * Create a naming context implementation to be used for this index + * using the naming context factory that was provided in the ctor + * for the index. + */ + TAO_Persistent_Naming_Context *create_naming_context_impl ( + PortableServer::POA_ptr poa, + const char *poa_id); + + /** * Destructor. The memory mapped file that was opened/created is * not deleted, since we want it to keep the state of the Naming * Service until the next run. @@ -161,6 +175,9 @@ private: /// The reference to the root Naming Context. CosNaming::NamingContext_var root_context_; + + /// The factory for constructing naming contexts within the index + TAO_Persistent_Naming_Context_Factory *context_impl_factory_; }; TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context.cpp b/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context.cpp index caa29847f7b..6a90a325ae9 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context.cpp +++ b/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context.cpp @@ -235,23 +235,6 @@ TAO_Persistent_Bindings_Map::shared_bind (const char * id, TAO_Persistent_Naming_Context::TAO_Persistent_Naming_Context (PortableServer::POA_ptr poa, const char *poa_id, - TAO_Persistent_Context_Index *context_index) - - : TAO_Hash_Naming_Context (poa, - poa_id), - counter_ (0), - persistent_context_ (0), - index_ (context_index) -{ - ACE_NEW (this->persistent_context_, - TAO_Persistent_Bindings_Map (context_index->orb ())); - - // Set the superclass pointer. - context_ = persistent_context_; -} - -TAO_Persistent_Naming_Context::TAO_Persistent_Naming_Context (PortableServer::POA_ptr poa, - const char *poa_id, TAO_Persistent_Context_Index *context_index, HASH_MAP *map, ACE_UINT32 *counter) @@ -267,7 +250,10 @@ TAO_Persistent_Naming_Context::TAO_Persistent_Naming_Context (PortableServer::PO // Set the superclass pointer. context_ = persistent_context_; - persistent_context_->set (map, index_->allocator ()); + // If a map was provided (i.e., not defaulted) then set it in the + // persistent_context_ + if (map != 0) + persistent_context_->set (map, index_->allocator ()); } int @@ -309,12 +295,13 @@ TAO_Persistent_Naming_Context::make_new_context (PortableServer::POA_ptr poa, // Put together a servant for the new Naming Context. - TAO_Persistent_Naming_Context *context_impl = 0; - ACE_NEW_THROW_EX (context_impl, - TAO_Persistent_Naming_Context (poa, - poa_id, - ind), - CORBA::NO_MEMORY ()); + TAO_Persistent_Naming_Context *context_impl = ind->create_naming_context_impl( + poa, + poa_id); + + // Verify that a context implementation was created. If not, throw an exception + if (context_impl == 0) + throw CORBA::NO_MEMORY (); // Put <context_impl> into the auto pointer temporarily, in case next // allocation fails. diff --git a/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context.h b/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context.h index 8659c497466..56e7a886c1f 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context.h +++ b/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context.h @@ -169,12 +169,6 @@ public: // = Initialization and termination methods. - /// Constructor. MUST be followed up by <init> to allocate the - /// underlying data structure from persistent storage! - TAO_Persistent_Naming_Context (PortableServer::POA_ptr poa, - const char *poa_id, - TAO_Persistent_Context_Index *context_index); - /// Allocate the underlying data structure from persistent storage. /// Returns 0 on success and -1 on failure. int init (size_t hash_table_size = ACE_DEFAULT_MAP_SIZE); @@ -182,13 +176,15 @@ public: /** * Constructor that takes in preallocated data structure and takes * ownership of it. This constructor is for 'recreating' servants - * from persistent state. + * from persistent state. If no map is provided, it MUST be followed + * up by <init> to allocate the underlying data structure from + * persistent storage! */ TAO_Persistent_Naming_Context (PortableServer::POA_ptr poa, const char *poa_id, TAO_Persistent_Context_Index *context_index, - HASH_MAP * map, - ACE_UINT32 *counter); + HASH_MAP * map = 0, + ACE_UINT32 *counter = 0); /// Destructor. virtual ~TAO_Persistent_Naming_Context (void); diff --git a/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context_Factory.cpp b/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context_Factory.cpp new file mode 100644 index 00000000000..6cc93bdef1f --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context_Factory.cpp @@ -0,0 +1,39 @@ +// $Id$ + +#include "orbsvcs/Naming/Persistent_Naming_Context_Factory.h" +#include "orbsvcs/Naming/Persistent_Naming_Context.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +/// Constructor. +TAO_Persistent_Naming_Context_Factory::TAO_Persistent_Naming_Context_Factory (void) +{ + +} + +/// Destructor. Does not deallocate the hash map: if an instance of +/// this class goes out of scope, its hash_map remains in persistent storage. +TAO_Persistent_Naming_Context_Factory::~TAO_Persistent_Naming_Context_Factory (void) +{ +} + + +/// Factory method for creating an implementation object for naming contexts +TAO_Persistent_Naming_Context* +TAO_Persistent_Naming_Context_Factory::create_naming_context_impl ( + PortableServer::POA_ptr poa, + const char *poa_id, + TAO_Persistent_Context_Index *context_index, + HASH_MAP * map, + ACE_UINT32 *counter) +{ + // Construct the naming context, forwarding the map and counter even if they + // are defaulted + return new (ACE_nothrow) TAO_Persistent_Naming_Context (poa, + poa_id, + context_index, + map, + counter); +} + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context_Factory.h b/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context_Factory.h new file mode 100644 index 00000000000..570536be79c --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/Persistent_Naming_Context_Factory.h @@ -0,0 +1,62 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Persistent_Naming_Context_Factory.h + * + * $Id$ + * + * @author Kevin Stanley stanleyk@ociweb.com> + */ +//============================================================================= + + +#ifndef TAO_PERSISTENT_NAMING_CONTEXT_FACTORY_H +#define TAO_PERSISTENT_NAMING_CONTEXT_FACTORY_H +#include /**/ "ace/pre.h" + +#include "tao/ORB.h" +#include "orbsvcs/Naming/nsconf.h" +#include "orbsvcs/Naming/naming_serv_export.h" +#include "orbsvcs/Naming/Hash_Naming_Context.h" +#include "orbsvcs/Naming/Persistent_Entries.h" +#include "orbsvcs/Naming/Persistent_Naming_Context.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +class TAO_Persistent_Naming_Context; + +/** + * @class TAO_Persistent_Naming_Context_Factory + * + * @brief A factory that creates TAO_Persistent_Naming_Context + * objects to implement the COS Naming Service NamingContext interface. + */ +class TAO_Naming_Serv_Export TAO_Persistent_Naming_Context_Factory +{ +public: + + // = Initialization and termination methods. + /// Data structure used by TAO_Persistent_Context_Index - typedef for ease of use. + typedef TAO_Persistent_Naming_Context::HASH_MAP HASH_MAP; + + /// Constructor. + TAO_Persistent_Naming_Context_Factory (void); + + /// Destructor. Does not deallocate the hash map: if an instance of + /// this class goes out of scope, its hash_map remains in persistent storage. + virtual ~TAO_Persistent_Naming_Context_Factory (void); + + /// Factory method for creating an implementation object for naming contexts + virtual TAO_Persistent_Naming_Context* + create_naming_context_impl (PortableServer::POA_ptr poa, + const char *poa_id, + TAO_Persistent_Context_Index *context_index, + HASH_MAP * map = 0, + ACE_UINT32 *counter = 0); +}; + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* TAO_PERSISTENT_NAMING_CONTEXT_FACTORY_H */ diff --git a/TAO/orbsvcs/orbsvcs/Naming/Storable.h b/TAO/orbsvcs/orbsvcs/Naming/Storable.h index 394a1863447..56755d18a0d 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Storable.h +++ b/TAO/orbsvcs/orbsvcs/Naming/Storable.h @@ -21,8 +21,9 @@ #pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ -#include "tao/Versioned_Namespace.h" +#include "tao/Storable_Base.h" #include "ace/SString.h" +#include "orbsvcs/Naming/naming_serv_export.h" TAO_BEGIN_VERSIONED_NAMESPACE_DECL @@ -68,7 +69,7 @@ class TAO_NS_Persistence_Record ACE_CString ref_; }; -class TAO_NS_Persistence_Global +class TAO_Naming_Serv_Export TAO_NS_Persistence_Global { public: void counter (unsigned int counter); @@ -78,84 +79,6 @@ class TAO_NS_Persistence_Global unsigned int counter_; }; -class TAO_Storable_Base -{ -public: - TAO_Storable_Base(); - - virtual ~TAO_Storable_Base(); - - virtual void remove() = 0; - - virtual int exists() = 0; - - virtual int open () = 0; - - virtual int close () = 0; - - virtual int flock (int whence, int start, int len) = 0; - - virtual int funlock (int whence, int start, int len) = 0; - - virtual time_t last_changed(void) = 0; - - // Mimic a portion of the std::ios interface. We need to be able - // to indicate error states from the extraction operators below. - enum Storable_State { goodbit = 0, - badbit = 1, - eofbit = 2, - failbit = 4 - }; - - void clear (Storable_State state = goodbit); - - void setstate (Storable_State state); - - Storable_State rdstate (void) const; - - bool good (void) const; - - bool bad (void) const; - - bool eof (void) const; - - bool fail (void) const; - - virtual TAO_Storable_Base& operator << ( - const TAO_NS_Persistence_Header& header) = 0; - - virtual TAO_Storable_Base& operator << ( - const TAO_NS_Persistence_Record& record) = 0; - - virtual TAO_Storable_Base& operator >> ( - TAO_NS_Persistence_Header& header) = 0; - - virtual TAO_Storable_Base& operator >> ( - TAO_NS_Persistence_Record& record) = 0; - - virtual TAO_Storable_Base& operator << ( - const TAO_NS_Persistence_Global& global) = 0; - - virtual TAO_Storable_Base& operator >> ( - TAO_NS_Persistence_Global& global) = 0; - -private: - Storable_State state_; -}; - -class TAO_Naming_Service_Persistence_Factory -{ -public: - TAO_Naming_Service_Persistence_Factory(); - - virtual ~TAO_Naming_Service_Persistence_Factory(); - - // Factory Methods - - virtual TAO_Storable_Base *create_stream(const ACE_CString & file, - const ACE_TCHAR * mode) = 0; -}; - TAO_END_VERSIONED_NAMESPACE_DECL #if defined (__ACE_INLINE__) diff --git a/TAO/orbsvcs/orbsvcs/Naming/Storable.inl b/TAO/orbsvcs/orbsvcs/Naming/Storable.inl index 2df1d497262..c020a68042e 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Storable.inl +++ b/TAO/orbsvcs/orbsvcs/Naming/Storable.inl @@ -99,69 +99,4 @@ TAO_NS_Persistence_Global::counter () const return this->counter_; } - -ACE_INLINE -TAO_Naming_Service_Persistence_Factory::TAO_Naming_Service_Persistence_Factory() -{ -} - -ACE_INLINE -TAO_Naming_Service_Persistence_Factory::~TAO_Naming_Service_Persistence_Factory() -{ -} - -ACE_INLINE -TAO_Storable_Base::TAO_Storable_Base() - : state_ (goodbit) -{ -} - -ACE_INLINE -TAO_Storable_Base::~TAO_Storable_Base() -{ -} - -ACE_INLINE void -TAO_Storable_Base::clear (TAO_Storable_Base::Storable_State state) -{ - this->state_ = state; -} - -ACE_INLINE void -TAO_Storable_Base::setstate (TAO_Storable_Base::Storable_State state) -{ - this->clear (static_cast <TAO_Storable_Base::Storable_State> ( - this->rdstate () | state)); -} - -ACE_INLINE TAO_Storable_Base::Storable_State -TAO_Storable_Base::rdstate (void) const -{ - return this->state_; -} - -ACE_INLINE bool -TAO_Storable_Base::good (void) const -{ - return (this->state_ == goodbit); -} - -ACE_INLINE bool -TAO_Storable_Base::bad (void) const -{ - return (this->state_ & badbit); -} - -ACE_INLINE bool -TAO_Storable_Base::eof (void) const -{ - return (this->state_ & eofbit); -} - -ACE_INLINE bool -TAO_Storable_Base::fail (void) const -{ - return (this->state_ & failbit); -} - TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context.cpp b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context.cpp index e37f995cce6..51415d75293 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context.cpp +++ b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context.cpp @@ -1,9 +1,13 @@ // $Id$ #include "orbsvcs/Naming/Storable_Naming_Context.h" +#include "orbsvcs/Naming/Storable_Naming_Context_Factory.h" +#include "orbsvcs/Naming/Storable_Naming_Context_ReaderWriter.h" #include "orbsvcs/Naming/Bindings_Iterator_T.h" #include "tao/debug.h" +#include "tao/Storable_Base.h" +#include "tao/Storable_Factory.h" #include "ace/Auto_Ptr.h" #include "ace/OS_NS_stdio.h" @@ -12,7 +16,7 @@ TAO_BEGIN_VERSIONED_NAMESPACE_DECL const char * TAO_Storable_Naming_Context::root_name_; ACE_UINT32 TAO_Storable_Naming_Context::gcounter_; -ACE_Auto_Ptr<TAO_Storable_Base> TAO_Storable_Naming_Context::gfl_; +ACE_Auto_Ptr<TAO::Storable_Base> TAO_Storable_Naming_Context::gfl_; int TAO_Storable_Naming_Context::redundant_; TAO_Storable_IntId::TAO_Storable_IntId (void) @@ -238,316 +242,138 @@ TAO_Storable_Bindings_Map::shared_bind (const char * id, } } -void TAO_Storable_Naming_Context::Write(TAO_Storable_Base& wrtr) +void TAO_Storable_Naming_Context::Write (TAO::Storable_Base& wrtr) { ACE_TRACE("Write"); - TAO_NS_Persistence_Header header; - - header.size (static_cast<unsigned int> (storable_context_->current_size())); - header.destroyed (destroyed_); - - wrtr << header; - - if (0u == header.size ()) - return; - - ACE_Hash_Map_Iterator<TAO_Storable_ExtId,TAO_Storable_IntId, - ACE_Null_Mutex> it = storable_context_->map().begin(); - ACE_Hash_Map_Iterator<TAO_Storable_ExtId,TAO_Storable_IntId, - ACE_Null_Mutex> itend = storable_context_->map().end(); - - ACE_Hash_Map_Entry<TAO_Storable_ExtId,TAO_Storable_IntId> ent = *it; - - while (!(it == itend)) - { - TAO_NS_Persistence_Record record; - - ACE_CString name; - CosNaming::BindingType bt = (*it).int_id_.type_; - if (bt == CosNaming::ncontext) - { - CORBA::Object_var - obj = orb_->string_to_object ((*it).int_id_.ref_.in ()); - if (obj->_is_collocated ()) - { - // This is a local (i.e. non federated context) we therefore - // store only the ObjectID (persistence filename) for the object. - - // The driving force behind storing ObjectIDs rather than IORs for - // local contexts is to provide for a redundant naming service. - // That is, a naming service that runs simultaneously on multiple - // machines sharing a file system. It allows multiple redundant - // copies to be started and stopped independently. - // The original target platform was Tru64 Clusters where there was - // a cluster address. In that scenario, clients may get different - // servers on each request, hence the requirement to keep - // synchronized to the disk. It also works on non-cluster system - // where the client picks one of the redundant servers and uses it, - // while other systems can pick different servers. (However in this - // scenario, if a server fails and a client must pick a new server, - // that client may not use any saved context IORs, instead starting - // from the root to resolve names. So this latter mode is not quite - // transparent to clients.) [Rich Seibel (seibel_r) of ociweb.com] - - PortableServer::ObjectId_var - oid = poa_->reference_to_id (obj.in ()); - CORBA::String_var - nm = PortableServer::ObjectId_to_string (oid.in ()); - const char - *newname = nm.in (); - name.set (newname); // The local ObjectID (persistance filename) - record.type (TAO_NS_Persistence_Record::LOCAL_NCONTEXT); - } - else - { - // Since this is a foreign (federated) context, we can not store - // the objectID (because it isn't in our storage), if we did, when - // we restore, we would end up either not finding a permanent - // record (and thus ending up incorrectly assuming the context was - // destroyed) or loading another context altogether (just because - // the contexts shares its objectID filename which is very likely). - // [Simon Massey (sma) of prismtech.com] - - name.set ((*it).int_id_.ref_.in ()); // The federated context IOR - record.type (TAO_NS_Persistence_Record::REMOTE_NCONTEXT); - } - } - else // if (bt == CosNaming::nobject) // shouldn't be any other, can there? - { - name.set ((*it).int_id_.ref_.in ()); // The non-context object IOR - record.type (TAO_NS_Persistence_Record::OBJREF); - } - record.ref(name); - - const char *myid = (*it).ext_id_.id(); - ACE_CString id(myid); - record.id(id); - - const char *mykind = (*it).ext_id_.kind(); - ACE_CString kind(mykind); - record.kind(kind); - - wrtr << record; - it.advance(); - } + TAO_Storable_Naming_Context_ReaderWriter rw(wrtr); + rw.write(*this); } -// Helper function to load a new context into the binding_map +// Helpers function to load a new context into the binding_map int -TAO_Storable_Naming_Context::load_map(File_Open_Lock_and_Check *flck) +TAO_Storable_Naming_Context::load_map (TAO::Storable_Base& storable) { ACE_TRACE("load_map"); - // assume file already open for reading - TAO_Storable_Bindings_Map *bindings_map; - - // create the new bindings map - ACE_NEW_THROW_EX (bindings_map, - TAO_Storable_Bindings_Map (hash_table_size_,orb_.in()), - CORBA::NO_MEMORY ()); - - // get the data for this bindings map from the file - - TAO_NS_Persistence_Header header; - TAO_NS_Persistence_Record record; + TAO_Storable_Naming_Context_ReaderWriter rw (storable); + return rw.read (*this); +} - // we are only using the size from this header - flck->peer() >> header; - if (!flck->peer ().good ()) +TAO_Storable_Naming_Context:: +File_Open_Lock_and_Check::File_Open_Lock_and_Check ( + TAO_Storable_Naming_Context * context, + Method_Type method_type) +: TAO::Storable_File_Guard (TAO_Storable_Naming_Context::redundant_), + context_(context) +{ + try { - flck->peer ().clear (); - throw CORBA::INTERNAL (); + this->init (method_type); } - - // reset the destroyed flag - this->destroyed_ = header.destroyed(); - - // read in the data for the map - for (unsigned int i= 0u; i<header.size(); ++i) + catch (const TAO::Storable_Read_Exception &) { - flck->peer() >> record; - if (!flck->peer ().good ()) - { - flck->peer ().clear (); - throw CORBA::INTERNAL (); - } - - if (TAO_NS_Persistence_Record::LOCAL_NCONTEXT == record.type ()) - { - PortableServer::ObjectId_var - id = PortableServer::string_to_ObjectId (record.ref ().c_str ()); - const char - *intf = interface_->_interface_repository_id (); - CORBA::Object_var - objref = poa_->create_reference_with_id (id.in (), intf); - bindings_map->bind ( record.id ().c_str (), - record.kind ().c_str (), - objref.in (), - CosNaming::ncontext ); - } - else - { - CORBA::Object_var - objref = orb_->string_to_object (record.ref ().c_str ()); - bindings_map->bind ( record.id ().c_str (), - record.kind ().c_str (), - objref.in (), - ((TAO_NS_Persistence_Record::REMOTE_NCONTEXT == record.type ()) - ? CosNaming::ncontext // REMOTE_NCONTEXT - : CosNaming::nobject )); // OBJREF - } + throw CORBA::INTERNAL (); } - storable_context_ = bindings_map; - context_ = storable_context_; - return 0; } TAO_Storable_Naming_Context:: -File_Open_Lock_and_Check::File_Open_Lock_and_Check( - TAO_Storable_Naming_Context * context, - const char * mode) -:closed_(1), - context_(context) +File_Open_Lock_and_Check::~File_Open_Lock_and_Check () { - ACE_TRACE("File_Open_Lock_and_Check"); - // We only accept a subset of mode argument, check it - rwflags_ = 0; - for( unsigned int i = 0; i<ACE_OS::strlen(mode); i++ ) - { - switch (mode[i]) + this->release (); + + // Check if a write occurred for this context and + // notify the context if it did. + if (context_->write_occurred_ == 1) { - case 'r': rwflags_ |= mode_read; - break; - case 'w': rwflags_ |= mode_write; - break; - case 'c': rwflags_ |= mode_create; - break; - default: rwflags_ = -1; + context_->context_written (); + // We have to make sure we clear the flag + // for subsequent times through. + context_->write_occurred_ = 0; } - } - if( rwflags_ <= 0 ) - { - errno = EINVAL; - throw CORBA::PERSIST_STORE(); - } - - // build the file name - ACE_CString file_name(context->persistence_directory_); - file_name += "/"; - file_name += context->name_; - - // Create the stream - fl_ = context->factory_->create_stream(file_name, ACE_TEXT_CHAR_TO_TCHAR(mode)); - if (TAO_Storable_Naming_Context::redundant_) - { - if (fl_->open() != 0) - { - delete fl_; - throw CORBA::PERSIST_STORE(); - } +} - // acquire a lock on it - if (fl_ -> flock(0, 0, 0) != 0) - { - fl_->close(); - delete fl_; - throw CORBA::INTERNAL(); - } +bool +TAO_Storable_Naming_Context:: +File_Open_Lock_and_Check::object_obsolete (void) +{ - // now that the file is successfully opened and locked it must be - // unlocked/closed before we leave this class - closed_ = 0; + // Query the underlying context if it is obsolete with respect + // to the provided file last-changed time + return (context_->is_obsolete (fl_->last_changed ())); +} - if ( ! (rwflags_ & mode_create) ) - { - // Check if our copy is up to date - time_t new_last_changed = fl_->last_changed(); - if( new_last_changed > context->last_changed_ ) - { - context->last_changed_ = new_last_changed; - // Throw our map away - delete context->storable_context_; - // and build a new one from disk - context->load_map(this); - } - } - } - else if ( ! context->storable_context_ || (rwflags_ & mode_write) ) - { - if (fl_->open() != 0) - { - delete fl_; - throw CORBA::PERSIST_STORE(); - } +void +TAO_Storable_Naming_Context:: +File_Open_Lock_and_Check::mark_object_current (void) +{ + // Reset the stale flag + context_->stale (false); + // Set the last update time to the file last update time + this->set_object_last_changed (fl_->last_changed ()); +} - // now that the file is successfully opened - // unlocked/closed before we leave this class - closed_ = 0; +void +TAO_Storable_Naming_Context:: +File_Open_Lock_and_Check::set_object_last_changed (const time_t & time) +{ + context_->last_changed_ = time; +} - if(!context->storable_context_) - { - // Load the map from disk - context->load_map(this); - } - } - else - { - // Need to insure that fl_ gets deleted - delete fl_; - } +time_t +TAO_Storable_Naming_Context:: +File_Open_Lock_and_Check::get_object_last_changed () +{ + return context_->last_changed_; } void TAO_Storable_Naming_Context:: -File_Open_Lock_and_Check::release(void) +File_Open_Lock_and_Check::load_from_stream () { - ACE_TRACE("release"); - if ( ! closed_ ) - { - // If we updated the disk, save the time stamp - if(TAO_Storable_Naming_Context::redundant_) - { - if( rwflags_ & mode_write ) - context_->last_changed_ = fl_->last_changed(); - fl_->funlock(0, 0, 0); - } - fl_->close(); - delete fl_; - closed_ = 1; - } + // Throw our map away + delete context_->storable_context_; + // and build a new one from disk + context_->load_map (this->peer()); } +bool TAO_Storable_Naming_Context:: -File_Open_Lock_and_Check::~File_Open_Lock_and_Check(void) +File_Open_Lock_and_Check::is_loaded_from_stream () { - ACE_TRACE("~File_Open_Lock_and_Check"); - this->release(); + return context_->storable_context_ != 0; } -TAO_Storable_Base & -TAO_Storable_Naming_Context::File_Open_Lock_and_Check::peer(void) +TAO::Storable_Base * +TAO_Storable_Naming_Context:: +File_Open_Lock_and_Check::create_stream (const char * mode) { - ACE_TRACE("peer"); - return *fl_; + ACE_CString file_name = context_->context_name_; + + // Create the stream + return context_->factory_->create_stream(file_name, ACE_TEXT_CHAR_TO_TCHAR(mode)); } +// Make shortcut to get to Method_Type enums +typedef TAO::Storable_File_Guard SFG; + TAO_Storable_Naming_Context::TAO_Storable_Naming_Context ( CORBA::ORB_ptr orb, PortableServer::POA_ptr poa, - const char *poa_id, - TAO_Naming_Service_Persistence_Factory *factory, - const ACE_TCHAR *persistence_directory, + const char *context_name, + TAO_Storable_Naming_Context_Factory *cxt_factory, + TAO::Storable_Factory *factory, size_t hash_table_size) : TAO_Hash_Naming_Context (poa, - poa_id), + context_name), counter_ (0), storable_context_ (0), orb_(CORBA::ORB::_duplicate (orb)), - name_ (poa_id), + context_name_ (context_name), poa_ (PortableServer::POA::_duplicate (poa)), - factory_(factory), - persistence_directory_ (ACE_TEXT_ALWAYS_CHAR(persistence_directory)), - hash_table_size_(hash_table_size), - last_changed_(0) + context_factory_ (cxt_factory), + factory_ (factory), + hash_table_size_ (hash_table_size), + last_changed_ (0), + write_occurred_ (0) { ACE_TRACE("TAO_Storable_Naming_Context"); } @@ -562,12 +388,10 @@ TAO_Storable_Naming_Context::~TAO_Storable_Naming_Context (void) if (this->destroyed_) { // Make sure we delete the associated stream - ACE_CString file_name (this->persistence_directory_); - file_name += "/"; - file_name += this->name_; + ACE_CString file_name = this->context_name_; // Now delete the file - ACE_Auto_Ptr<TAO_Storable_Base> + ACE_Auto_Ptr<TAO::Storable_Base> fl ( this->factory_->create_stream(file_name.c_str(), ACE_TEXT("r")) @@ -586,10 +410,9 @@ CosNaming::NamingContext_ptr TAO_Storable_Naming_Context::make_new_context ( CORBA::ORB_ptr orb, PortableServer::POA_ptr poa, - const char *poa_id, - size_t context_size, - TAO_Naming_Service_Persistence_Factory *factory, - const ACE_TCHAR *persistence_directory, + const char *context_name, + TAO_Storable_Naming_Context_Factory *cxt_factory, + TAO::Storable_Factory *pers_factory, TAO_Storable_Naming_Context **new_context) { ACE_TRACE("make_new_context"); @@ -598,15 +421,14 @@ TAO_Storable_Naming_Context::make_new_context ( // Put together a servant for the new Naming Context. - TAO_Storable_Naming_Context *context_impl = 0; - ACE_NEW_THROW_EX (context_impl, - TAO_Storable_Naming_Context (orb, - poa, - poa_id, - factory, - persistence_directory, - context_size), - CORBA::NO_MEMORY ()); + TAO_Storable_Naming_Context *context_impl = + cxt_factory->create_naming_context_impl (orb, + poa, + context_name, + pers_factory); + + if (context_impl == 0) + throw CORBA::NO_MEMORY (); // Put <context_impl> into the auto pointer temporarily, in case next // allocation fails. @@ -627,7 +449,7 @@ TAO_Storable_Naming_Context::make_new_context ( // Register the new context with the POA. PortableServer::ObjectId_var id = - PortableServer::string_to_ObjectId (poa_id); + PortableServer::string_to_ObjectId (context_name); // If we try to register a naming context that is already registered, // the following activation causes a POA::ObjectAlreadyActive exception be @@ -663,7 +485,7 @@ TAO_Storable_Naming_Context::new_context (void) { // Open the backing file - File_Open_Lock_and_Check flck(this, "r"); + File_Open_Lock_and_Check flck(this, SFG::ACCESSOR); // Check to make sure this object didn't have <destroy> method // invoked on it. @@ -672,8 +494,8 @@ TAO_Storable_Naming_Context::new_context (void) } TAO_NS_Persistence_Global global; + TAO_Storable_Naming_Context_ReaderWriter rw(*gfl_.get()); - // Generate a POA id for the new context. if(redundant_) { // acquire a lock on the file that holds our counter @@ -685,25 +507,21 @@ TAO_Storable_Naming_Context::new_context (void) if (gfl_ -> flock(0, 0, 0) != 0) throw CORBA::INTERNAL(); // get the counter from disk - *gfl_.get() >> global; - if (!gfl_.get ()->good () && - gfl_.get ()->rdstate () != TAO_Storable_Base::eofbit) - { - gfl_.get ()->clear (); - throw CORBA::INTERNAL (); - } + rw.read_global(global); gcounter_ = global.counter(); // use it to generate a new name } - char poa_id[BUFSIZ]; - ACE_OS::sprintf (poa_id, + + // Generate an Object id for the new context. + char object_id[BUFSIZ]; + ACE_OS::sprintf (object_id, "%s_%d", root_name_, gcounter_++); // then save it back on disk - global.counter(gcounter_); - *gfl_.get() << global; - if(redundant_) + global.counter (gcounter_); + rw.write_global (global); + if (redundant_) { // and release our lock if (gfl_ -> flock(0, 0, 0) != 0) @@ -716,10 +534,9 @@ TAO_Storable_Naming_Context::new_context (void) CosNaming::NamingContext_var result = make_new_context (this->orb_.in (), this->poa_.in (), - poa_id, - this->storable_context_->total_size (), + object_id, + this->context_factory_, this->factory_, - ACE_TEXT_CHAR_TO_TCHAR (this->persistence_directory_.c_str ()), &new_context); // Since this is a new context, make an empty map in it @@ -728,7 +545,7 @@ TAO_Storable_Naming_Context::new_context (void) CORBA::NO_MEMORY ()); new_context->context_ = new_context->storable_context_; - File_Open_Lock_and_Check flck(new_context, "wc"); + File_Open_Lock_and_Check flck(new_context, SFG::CREATE_WITHOUT_FILE); new_context->Write(flck.peer()); return result._retn (); @@ -752,7 +569,7 @@ TAO_Storable_Naming_Context::rebind (const CosNaming::Name& n, CORBA::INTERNAL ()); // Open the backing file - File_Open_Lock_and_Check flck(this, name_len > 1 ? "r" : "rw"); + File_Open_Lock_and_Check flck(this, name_len > 1 ? SFG::ACCESSOR : SFG::MUTATOR); // Check to make sure this object didn't have <destroy> method // invoked on it. @@ -819,7 +636,7 @@ TAO_Storable_Naming_Context::bind_context (const CosNaming::Name &n, CORBA::INTERNAL ()); // Open the backing file - File_Open_Lock_and_Check flck(this, name_len > 1 ? "r" : "rw"); + File_Open_Lock_and_Check flck(this, name_len > 1 ? SFG::ACCESSOR : SFG::MUTATOR); // Check to make sure this object didn't have <destroy> method // invoked on it. @@ -879,7 +696,7 @@ TAO_Storable_Naming_Context::rebind_context (const CosNaming::Name &n, CORBA::INTERNAL ()); // Open the backing file - File_Open_Lock_and_Check flck(this, name_len > 1 ? "r" : "rw"); + File_Open_Lock_and_Check flck(this, name_len > 1 ? SFG::ACCESSOR : SFG::MUTATOR); // Check to make sure this object didn't have <destroy> method // invoked on it. @@ -938,7 +755,7 @@ TAO_Storable_Naming_Context::resolve (const CosNaming::Name& n) CORBA::INTERNAL ()); // Open the backing file - File_Open_Lock_and_Check flck(this, "r"); + File_Open_Lock_and_Check flck(this, SFG::ACCESSOR); // Check to make sure this object didn't have <destroy> method // invoked on it. @@ -1027,7 +844,8 @@ TAO_Storable_Naming_Context::unbind (const CosNaming::Name& n) CORBA::INTERNAL ()); // Open the backing file - File_Open_Lock_and_Check flck(this, name_len > 1 ? "r" : "rw"); + File_Open_Lock_and_Check flck(this, name_len > 1 ? + SFG::ACCESSOR : SFG::MUTATOR); // Check to make sure this object didn't have <destroy> method // invoked on it. @@ -1086,7 +904,8 @@ TAO_Storable_Naming_Context::bind_new_context (const CosNaming::Name& n) throw CORBA::OBJECT_NOT_EXIST (); // Open the backing file - File_Open_Lock_and_Check flck(this, name_len > 1 ? "r" : "rw"); + File_Open_Lock_and_Check flck(this, name_len > 1 ? + SFG::ACCESSOR : SFG::MUTATOR); // Check to make sure this object didn't have <destroy> method // invoked on it. @@ -1155,7 +974,7 @@ TAO_Storable_Naming_Context::destroy (void) CORBA::INTERNAL ()); // Open the backing file - File_Open_Lock_and_Check flck(this, "rw"); + File_Open_Lock_and_Check flck(this, SFG::MUTATOR); // Check to make sure this object didn't have <destroy> method // invoked on it. @@ -1190,6 +1009,21 @@ TAO_Storable_Naming_Context::destroy (void) } } +void +TAO_Storable_Naming_Context::context_written (void) +{ + // No-op. Overridden by derived class. +} + +bool +TAO_Storable_Naming_Context::is_obsolete (time_t stored_time) +{ + // If the context_ has not been populated or + // the time in the persistent store is greater than this + // object last change time, the context is obsolete + return (this->context_ == 0) || + (stored_time > this->last_changed_); +} void TAO_Storable_Naming_Context::bind (const CosNaming::Name& n, @@ -1209,7 +1043,8 @@ TAO_Storable_Naming_Context::bind (const CosNaming::Name& n, CORBA::INTERNAL ()); // Open the backing file - File_Open_Lock_and_Check flck(this, name_len > 1 ? "r" : "rw"); + File_Open_Lock_and_Check flck(this, name_len > 1 ? + SFG::ACCESSOR : SFG::MUTATOR); // Check to make sure this object didn't have <destroy> method // invoked on it. @@ -1247,7 +1082,7 @@ TAO_Storable_Naming_Context::bind (const CosNaming::Name& n, else if (result == -1) throw CORBA::INTERNAL (); - this->Write(flck.peer()); + this->Write (flck.peer()); } } @@ -1272,7 +1107,7 @@ TAO_Storable_Naming_Context::list (CORBA::ULong how_many, CORBA::INTERNAL ()); // Open the backing file - File_Open_Lock_and_Check flck(this, "r"); + File_Open_Lock_and_Check flck(this, SFG::ACCESSOR); // Check to make sure this object didn't have <destroy> method // invoked on it. @@ -1382,14 +1217,14 @@ TAO_END_VERSIONED_NAMESPACE_DECL TAO_BEGIN_VERSIONED_NAMESPACE_DECL -CosNaming::NamingContext_ptr TAO_Storable_Naming_Context::recreate_all( +CosNaming::NamingContext_ptr TAO_Storable_Naming_Context::recreate_all ( CORBA::ORB_ptr orb, PortableServer::POA_ptr poa, const char *poa_id, size_t context_size, int reentering, - TAO_Naming_Service_Persistence_Factory *factory, - const ACE_TCHAR *persistence_directory, + TAO_Storable_Naming_Context_Factory *cxt_factory, + TAO::Storable_Factory *pers_factory, int use_redundancy) { ACE_TRACE("recreate_all"); @@ -1408,20 +1243,18 @@ CosNaming::NamingContext_ptr TAO_Storable_Naming_Context::recreate_all( make_new_context (orb, poa, poa_id, - context_size, - factory, - persistence_directory, + cxt_factory, + pers_factory, &new_context); // Now does this already exist on disk? - ACE_TString file_name(persistence_directory); - file_name += ACE_TEXT("/"); - file_name += ACE_TEXT_CHAR_TO_TCHAR(poa_id); - ACE_Auto_Ptr<TAO_Storable_Base> fl (factory->create_stream(ACE_TEXT_ALWAYS_CHAR(file_name.c_str()), ACE_TEXT("r"))); - if (fl->exists()) + ACE_TString file_name = ACE_TEXT_CHAR_TO_TCHAR(poa_id); + ACE_Auto_Ptr<TAO::Storable_Base> fl ( + pers_factory->create_stream (ACE_TEXT_ALWAYS_CHAR (file_name.c_str ()), ACE_TEXT ("r"))); + if (fl->exists ()) { // Load the map from disk - File_Open_Lock_and_Check flck(new_context, "r"); + File_Open_Lock_and_Check flck (new_context, SFG::CREATE_WITH_FILE); } else { @@ -1430,15 +1263,20 @@ CosNaming::NamingContext_ptr TAO_Storable_Naming_Context::recreate_all( TAO_Storable_Bindings_Map (context_size,orb), CORBA::NO_MEMORY ()); new_context->context_ = new_context->storable_context_; - File_Open_Lock_and_Check flck(new_context, "wc"); - new_context->Write(flck.peer()); + File_Open_Lock_and_Check flck (new_context, SFG::CREATE_WITHOUT_FILE); + new_context->Write (flck.peer ()); } // build the global file name file_name += ACE_TEXT("_global"); - // Create the stream for the counter used to uniquely creat context names - gfl_.reset(factory->create_stream(ACE_TEXT_ALWAYS_CHAR(file_name.c_str()), ACE_TEXT("crw"))); + // Create the stream for the counter used to uniquely create context names + // Pass false for use_backup since access to this file is not wrapped + // around a Storable_File_Guard derived class. + gfl_.reset(pers_factory-> + create_stream (ACE_TEXT_ALWAYS_CHAR(file_name.c_str()), + ACE_TEXT("crw"), + false)); if (gfl_->open() != 0) { delete gfl_.release(); @@ -1447,13 +1285,8 @@ CosNaming::NamingContext_ptr TAO_Storable_Naming_Context::recreate_all( // get the counter from disk TAO_NS_Persistence_Global global; - *gfl_.get() >> global; - if (!gfl_.get ()->good () && - gfl_.get ()->rdstate () != TAO_Storable_Base::eofbit) - { - gfl_.get ()->clear (); - throw CORBA::INTERNAL (); - } + TAO_Storable_Naming_Context_ReaderWriter rw(*gfl_.get()); + rw.read_global(global); gcounter_ = global.counter(); if(redundant_) gfl_->close(); diff --git a/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context.h b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context.h index fe4d33ae149..9d28d4d4c31 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context.h +++ b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context.h @@ -15,6 +15,7 @@ #include /**/ "ace/pre.h" #include "orbsvcs/Naming/Hash_Naming_Context.h" +#include "tao/Storable_File_Guard.h" #include "ace/Hash_Map_Manager.h" #include "ace/Auto_Ptr.h" @@ -26,6 +27,14 @@ TAO_BEGIN_VERSIONED_NAMESPACE_DECL +namespace TAO +{ + class Storable_Base; + class Storable_Factory; +} + +class TAO_Storable_Naming_Context_Factory; + class TAO_Naming_Serv_Export TAO_Storable_IntId { public: @@ -229,8 +238,8 @@ public: TAO_Storable_Naming_Context (CORBA::ORB_ptr orb, PortableServer::POA_ptr poa, const char *poa_id, - TAO_Naming_Service_Persistence_Factory *factory, - const ACE_TCHAR *persistence_directory, + TAO_Storable_Naming_Context_Factory *cxt_factory, + TAO::Storable_Factory *factory, size_t hash_table_size = ACE_DEFAULT_MAP_SIZE); /// Destructor. @@ -247,22 +256,21 @@ public: static CosNaming::NamingContext_ptr make_new_context ( CORBA::ORB_ptr orb, PortableServer::POA_ptr poa, - const char *poa_id, - size_t context_size, - TAO_Naming_Service_Persistence_Factory *factory, - const ACE_TCHAR *persistence_directory, + const char *context_id, + TAO_Storable_Naming_Context_Factory *cxt_factory, + TAO::Storable_Factory *pers_factory, TAO_Storable_Naming_Context **new_context); // = Methods not implemented in TAO_Hash_Naming_Context. - static CosNaming::NamingContext_ptr recreate_all( + static CosNaming::NamingContext_ptr recreate_all ( CORBA::ORB_ptr orb, PortableServer::POA_ptr poa, - const char *poa_id, + const char *context_id, size_t context_size, int reentering, - TAO_Naming_Service_Persistence_Factory *factory, - const ACE_TCHAR *persistence_directory, + TAO_Storable_Naming_Context_Factory *cxt_factory, + TAO::Storable_Factory *pers_factory, int use_redundancy); @@ -353,6 +361,21 @@ public: protected: + /** + * An internal callback invoked by the File_Open_Lock_and_Check object to + * signal that this context was updated and written to disk. + * This will have been done after the file is closed. Check the + * last_changed_ attribute for the time of the write. + */ + virtual void context_written (void); + + /** + * An internal callback invoked by the File_Open_Lock_and_Check + * object to determine if this context is obsolete with respect to the + * file object . + */ + virtual bool is_obsolete (time_t stored_time); + /// Global counter used for generation of POA ids for children Naming /// Contexts. static ACE_UINT32 gcounter_; @@ -371,11 +394,16 @@ protected: CORBA::ORB_var orb_; - ACE_CString name_; + /// The name of the context used as its object id when registered + /// with the POA. + ACE_CString context_name_; + /// The POA that this context was registered with. PortableServer::POA_var poa_; - TAO_Naming_Service_Persistence_Factory *factory_; + TAO_Storable_Naming_Context_Factory *context_factory_; + + TAO::Storable_Factory *factory_; /// The directory in which to store the files ACE_CString persistence_directory_; @@ -386,73 +414,72 @@ protected: /// Disk time that match current memory state time_t last_changed_; - /// Flag to tell use whether we are redundant or not + /// Flag to tell us whether we are redundant or not static int redundant_; static const char * root_name_; /// The pointer to the global file used to allocate new contexts - static ACE_Auto_Ptr<TAO_Storable_Base> gfl_; + static ACE_Auto_Ptr<TAO::Storable_Base> gfl_; /** * @class File_Open_Lock_and_Check * - * @brief Helper class for the TAO_Storable_Naming_Context. - * - * Guard class for the TAO_Storable_Naming_Context. It opens - * a file for read/write and sets a lock on it. It then checks - * if the file has changed and re-reads it if it has. + * @brief File guard specific for storable naming contexts. * - * The destructor insures that the lock gets released. - * - * <pre> - * How to use this class: - * File_Open_Lock_and_Check flck(this, name_len > 1 ? "r" : "rw"); - * </pre> */ -class File_Open_Lock_and_Check +class TAO_Naming_Serv_Export File_Open_Lock_and_Check : +public TAO::Storable_File_Guard { public: /// Constructor - we always need the object which we guard. - File_Open_Lock_and_Check(TAO_Storable_Naming_Context * context, - const char * mode); + File_Open_Lock_and_Check (TAO_Storable_Naming_Context * context, + Method_Type method_type); + + ~File_Open_Lock_and_Check (); + +protected: + + /// Check if the guarded object is current with the last + /// update which could have been performed independently of + /// the owner of this object. + virtual bool object_obsolete (void); + + /// Mark the object as current with respect to the + /// file to which it was persisted. + virtual void mark_object_current (void); - /// Destructor - ~File_Open_Lock_and_Check(void); + /// Mark the time at which the object was modified and + virtual void set_object_last_changed (const time_t & time); - /// Releases the lock, closes the file, and deletes the I/O stream. - void release(void); + /// Get the time which the object was last written to the + /// file. + virtual time_t get_object_last_changed (); - /// Returns the stream to read/write on - TAO_Storable_Base & peer(void); + virtual void load_from_stream (); + + virtual bool is_loaded_from_stream (); + + virtual TAO::Storable_Base * create_stream (const char * mode); private: /// Default constructor File_Open_Lock_and_Check(void); - /// A flag to keep us from trying to close things more than once. - int closed_; - - /// We need to save the pointer to our parent for cleaning up TAO_Storable_Naming_Context * context_; - /// The pointer to the actual file I/O (bridge pattern) - TAO_Storable_Base *fl_; - - /// The flags that we were opened with - int rwflags_; - - /// Symbolic values for the flags in the above - enum{ mode_write = 1, mode_read = 2, mode_create = 4 }; }; // end of embedded class File_Open_Lock_and_Check friend class File_Open_Lock_and_Check; + friend class TAO_Storable_Naming_Context_ReaderWriter; - int load_map(File_Open_Lock_and_Check *flck); + int load_map(TAO::Storable_Base& storable); - void Write(TAO_Storable_Base& wrtr); + void Write(TAO::Storable_Base& wrtr); + /// Is set by the Write operation. Used to determine + int write_occurred_; }; TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Activator.cpp b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Activator.cpp index 5f5f31a4530..28a52a40254 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Activator.cpp +++ b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Activator.cpp @@ -14,26 +14,29 @@ #if (TAO_HAS_MINIMUM_POA == 0) && !defined (CORBA_E_COMPACT) && !defined (CORBA_E_MICRO) #include "orbsvcs/Naming/Naming_Context_Interface.h" #include "orbsvcs/Naming/Storable_Naming_Context.h" +#include "orbsvcs/Naming/Storable_Naming_Context_Factory.h" #include "orbsvcs/Naming/Storable.h" +#include "tao/Storable_Factory.h" #include "ace/Auto_Ptr.h" TAO_BEGIN_VERSIONED_NAMESPACE_DECL TAO_Storable_Naming_Context_Activator::TAO_Storable_Naming_Context_Activator ( CORBA::ORB_ptr orb, - TAO_Naming_Service_Persistence_Factory *factory, - const ACE_TCHAR *persistence_directory, - size_t context_size) + TAO::Storable_Factory *persistence_factory, + TAO_Storable_Naming_Context_Factory *context_impl_factory, + const ACE_TCHAR *persistence_directory) : orb_(orb), - factory_(factory), - persistence_directory_(persistence_directory), - context_size_(context_size) + persistence_factory_(persistence_factory), + context_impl_factory_(context_impl_factory), + persistence_directory_(persistence_directory) { } TAO_Storable_Naming_Context_Activator::~TAO_Storable_Naming_Context_Activator () { - delete factory_; + delete persistence_factory_; + delete this->context_impl_factory_; } PortableServer::Servant @@ -43,7 +46,10 @@ TAO_Storable_Naming_Context_Activator::incarnate ( { // Make sure complete initialization has been done - ACE_ASSERT (factory_ != 0); + ACE_ASSERT (persistence_factory_ != 0); + + // Make sure complete initialization has been done + ACE_ASSERT (context_impl_factory_ != 0); CORBA::String_var poa_id = PortableServer::ObjectId_to_string (oid); @@ -53,29 +59,25 @@ TAO_Storable_Naming_Context_Activator::incarnate ( // context is accessed it will be determined that the contents of // the persistence elment needs to be read in. - // Does this already exist on disk? - ACE_TString file_name(persistence_directory_); - file_name += ACE_TEXT("/"); - file_name += ACE_TEXT_CHAR_TO_TCHAR(poa_id.in()); - TAO_Storable_Base * fl = factory_->create_stream(ACE_TEXT_ALWAYS_CHAR(file_name.c_str()), ACE_TEXT("rw")); - if (!fl->exists()) { - throw CORBA::OBJECT_NOT_EXIST (); - } + { // Does this already exist on disk? - // Store the stub we will return here. - CosNaming::NamingContext_var result (CosNaming::NamingContext::_nil()); + ACE_TString file_name = ACE_TEXT_CHAR_TO_TCHAR (poa_id.in ()); + ACE_Auto_Ptr<TAO::Storable_Base> fl ( + persistence_factory_->create_stream (ACE_TEXT_ALWAYS_CHAR (file_name.c_str ()), + ACE_TEXT ("rw"))); - // Put together a servant for the new Naming Context. + if (!fl->exists()) { + throw CORBA::OBJECT_NOT_EXIST (); + } + } - TAO_Storable_Naming_Context *context_impl = 0; - ACE_NEW_THROW_EX (context_impl, - TAO_Storable_Naming_Context (orb_, - poa, - poa_id.in (), - factory_, - persistence_directory_, - context_size_), - CORBA::NO_MEMORY ()); + // Put together a servant for the new Naming Context. + // Will throw NO_MEMORY exception if unable to construct one + TAO_Storable_Naming_Context *context_impl = + this->context_impl_factory_->create_naming_context_impl (orb_, + poa, + poa_id.in (), + persistence_factory_); // Put <context_impl> into the auto pointer temporarily, in case next // allocation fails. diff --git a/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Activator.h b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Activator.h index d4770ed1c60..d7cbfeb79ba 100644 --- a/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Activator.h +++ b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Activator.h @@ -26,7 +26,12 @@ TAO_BEGIN_VERSIONED_NAMESPACE_DECL -class TAO_Naming_Service_Persistence_Factory; +namespace TAO +{ + class Storable_Factory; +} + +class TAO_Storable_Naming_Context_Factory; /** * A servant activator to be use with a TAO_Storable_Naming_Context. @@ -43,10 +48,11 @@ public: * The constructor takes arguments needed to create a * TAO_Storable_Naming_Context and TAO_Naming_Context on demand. */ - TAO_Storable_Naming_Context_Activator(CORBA::ORB_ptr orb, - TAO_Naming_Service_Persistence_Factory *factory, - const ACE_TCHAR *persistence_directory, - size_t context_size); + TAO_Storable_Naming_Context_Activator ( + CORBA::ORB_ptr orb, + TAO::Storable_Factory *factory, + TAO_Storable_Naming_Context_Factory *context_impl_factory, + const ACE_TCHAR *persistence_directory); virtual ~TAO_Storable_Naming_Context_Activator(); @@ -70,9 +76,14 @@ public: private: CORBA::ORB_ptr orb_; - TAO_Naming_Service_Persistence_Factory *factory_; + + /// The factory for constructing the persistence mechanism for the contexts + TAO::Storable_Factory *persistence_factory_; + + /// The factory for constructing naming contexts within the index + TAO_Storable_Naming_Context_Factory *context_impl_factory_; + const ACE_TCHAR *persistence_directory_; - size_t context_size_; }; TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Factory.cpp b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Factory.cpp new file mode 100644 index 00000000000..78a91dd1a57 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Factory.cpp @@ -0,0 +1,49 @@ +// $Id$ + +#include "orbsvcs/Naming/Storable_Naming_Context_Factory.h" +#include "orbsvcs/Naming/Storable_Naming_Context.h" + +#include "tao/Storable_Factory.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +/// Constructor. +TAO_Storable_Naming_Context_Factory::TAO_Storable_Naming_Context_Factory ( + size_t hash_table_size) +: context_size_(hash_table_size) +{ + +} + +/// Destructor. Does not deallocate the hash map: if an instance of +/// this class goes out of scope, its hash_map remains in persistent storage. +TAO_Storable_Naming_Context_Factory::~TAO_Storable_Naming_Context_Factory (void) +{ + +} + + +TAO_Storable_Naming_Context* +TAO_Storable_Naming_Context_Factory::create_naming_context_impl ( + CORBA::ORB_ptr orb, + PortableServer::POA_ptr poa, + const char *poa_id, + TAO::Storable_Factory *persistence_factory) +{ + // Construct the naming context, forwarding the map and counter even if they + // are defaulted + TAO_Storable_Naming_Context *context_impl; + ACE_NEW_THROW_EX (context_impl, + TAO_Storable_Naming_Context (orb, + poa, + poa_id, + this, + persistence_factory, + this->context_size_), + CORBA::NO_MEMORY ()); + + return context_impl; +} + + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Factory.h b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Factory.h new file mode 100644 index 00000000000..748bd60f772 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_Factory.h @@ -0,0 +1,72 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Storable_Naming_Context_Factory.h + * + * $Id$ + * + * @author Kevin Stanley stanleyk@ociweb.com> + */ +//============================================================================= + + +#ifndef TAO_STORABLE_NAMING_CONTEXT_FACTORY_H +#define TAO_STORABLE_NAMING_CONTEXT_FACTORY_H +#include /**/ "ace/pre.h" + +#include "tao/ORB.h" +#include "orbsvcs/Naming/nsconf.h" +#include "orbsvcs/Naming/naming_serv_export.h" +#include "orbsvcs/Naming/Hash_Naming_Context.h" +#include "orbsvcs/Naming/Storable_Naming_Context.h" + +namespace TAO +{ + class Storable_Factory; +} + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class TAO_Storable_Naming_Context_Factory + * + * @brief + */ +class TAO_Naming_Serv_Export TAO_Storable_Naming_Context_Factory +{ +public: + + /// Data structure used by TAO_Persistent_Context_Index + /// - typedef for ease of use. + typedef TAO_Storable_Naming_Context::HASH_MAP HASH_MAP; + + // = Initialization and termination methods. + + /// Constructor. + TAO_Storable_Naming_Context_Factory ( + size_t hash_table_size = ACE_DEFAULT_MAP_SIZE); + + /// Destructor. Does not deallocate the hash map: if an instance of + /// this class goes out of scope, its hash_map remains in persistent storage. + virtual ~TAO_Storable_Naming_Context_Factory (void); + + /// Factory method for creating an implementation object for naming contexts. + /// If an existing naming context implementation is being rebuilt, the map + /// and counter parameters should be provided to the underlying HASH_MAP + /// implementation + virtual TAO_Storable_Naming_Context* create_naming_context_impl ( + CORBA::ORB_ptr orb, + PortableServer::POA_ptr poa, + const char *poa_id, + TAO::Storable_Factory *factory); + +protected: + /// The size for persisted naming context objects in hash map + size_t context_size_; +}; + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* TAO_STORABLE_NAMING_CONTEXT_FACTORY_H */ diff --git a/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_ReaderWriter.cpp b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_ReaderWriter.cpp new file mode 100644 index 00000000000..c21b331f6d9 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_ReaderWriter.cpp @@ -0,0 +1,270 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Storable_Naming_Context_ReaderWriter.cpp + * + * $Id$ + * + * @author Marina Spivak <marina@cs.wustl.edu> + * @author Byron Harris <harrisb@ociweb.com> + */ +//============================================================================= + +#include "orbsvcs/Naming/Storable_Naming_Context_ReaderWriter.h" +#include "orbsvcs/Naming/Storable_Naming_Context.h" +#include "orbsvcs/Naming/Storable.h" + +#include "tao/Storable_Base.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +TAO_Storable_Naming_Context_ReaderWriter:: +TAO_Storable_Naming_Context_ReaderWriter (TAO::Storable_Base & stream) + : stream_(stream) +{ +} + +void +TAO_Storable_Naming_Context_ReaderWriter::write (TAO_Storable_Naming_Context & context) +{ + TAO_NS_Persistence_Header header; + + header.size (static_cast<unsigned int> (context.storable_context_->current_size())); + header.destroyed (context.destroyed_); + + this->write_header(header); + + if (0u == header.size ()) + return; + + ACE_Hash_Map_Iterator<TAO_Storable_ExtId,TAO_Storable_IntId, + ACE_Null_Mutex> it = context.storable_context_->map().begin(); + ACE_Hash_Map_Iterator<TAO_Storable_ExtId,TAO_Storable_IntId, + ACE_Null_Mutex> itend = context.storable_context_->map().end(); + + ACE_Hash_Map_Entry<TAO_Storable_ExtId,TAO_Storable_IntId> ent = *it; + + while (!(it == itend)) + { + TAO_NS_Persistence_Record record; + + ACE_CString name; + CosNaming::BindingType bt = (*it).int_id_.type_; + if (bt == CosNaming::ncontext) + { + CORBA::Object_var + obj = context.orb_->string_to_object ((*it).int_id_.ref_.in ()); + if (obj->_is_collocated ()) + { + // This is a local (i.e. non federated context) we therefore + // store only the ObjectID (persistence filename) for the object. + + // The driving force behind storing ObjectIDs rather than IORs for + // local contexts is to provide for a redundant naming service. + // That is, a naming service that runs simultaneously on multiple + // machines sharing a file system. It allows multiple redundant + // copies to be started and stopped independently. + // The original target platform was Tru64 Clusters where there was + // a cluster address. In that scenario, clients may get different + // servers on each request, hence the requirement to keep + // synchronized to the disk. It also works on non-cluster system + // where the client picks one of the redundant servers and uses it, + // while other systems can pick different servers. (However in this + // scenario, if a server fails and a client must pick a new server, + // that client may not use any saved context IORs, instead starting + // from the root to resolve names. So this latter mode is not quite + // transparent to clients.) [Rich Seibel (seibel_r) of ociweb.com] + + PortableServer::ObjectId_var + oid = context.poa_->reference_to_id (obj.in ()); + CORBA::String_var + nm = PortableServer::ObjectId_to_string (oid.in ()); + const char + *newname = nm.in (); + name.set (newname); // The local ObjectID (persistance filename) + record.type (TAO_NS_Persistence_Record::LOCAL_NCONTEXT); + } + else + { + // Since this is a foreign (federated) context, we can not store + // the objectID (because it isn't in our storage), if we did, when + // we restore, we would end up either not finding a permanent + // record (and thus ending up incorrectly assuming the context was + // destroyed) or loading another context altogether (just because + // the contexts shares its objectID filename which is very likely). + // [Simon Massey (sma) of prismtech.com] + + name.set ((*it).int_id_.ref_.in ()); // The federated context IOR + record.type (TAO_NS_Persistence_Record::REMOTE_NCONTEXT); + } + } + else // if (bt == CosNaming::nobject) // shouldn't be any other, can there? + { + name.set ((*it).int_id_.ref_.in ()); // The non-context object IOR + record.type (TAO_NS_Persistence_Record::OBJREF); + } + record.ref(name); + + const char *myid = (*it).ext_id_.id(); + ACE_CString id(myid); + record.id(id); + + const char *mykind = (*it).ext_id_.kind(); + ACE_CString kind(mykind); + record.kind(kind); + + write_record (record); + it.advance(); + } + + context.write_occurred_ = 1; +} + +int +TAO_Storable_Naming_Context_ReaderWriter::read (TAO_Storable_Naming_Context & context) +{ + // assume file already open for reading + TAO_Storable_Bindings_Map *bindings_map; + + // create the new bindings map + ACE_NEW_THROW_EX (bindings_map, + TAO_Storable_Bindings_Map (context.hash_table_size_, context.orb_.in()), + CORBA::NO_MEMORY ()); + + // get the data for this bindings map from the file + + TAO_NS_Persistence_Header header; + TAO_NS_Persistence_Record record; + + // we are only using the size from this header + this->read_header(header); + + // reset the destroyed flag + context.destroyed_ = header.destroyed(); + + // read in the data for the map + for (unsigned int i= 0u; i<header.size(); ++i) + { + this->read_record(record); + + if (TAO_NS_Persistence_Record::LOCAL_NCONTEXT == record.type ()) + { + PortableServer::ObjectId_var + id = PortableServer::string_to_ObjectId (record.ref ().c_str ()); + const char + *intf = context.interface_->_interface_repository_id (); + CORBA::Object_var + objref = context.poa_->create_reference_with_id (id.in (), intf); + bindings_map->bind ( record.id ().c_str (), + record.kind ().c_str (), + objref.in (), + CosNaming::ncontext ); + } + else + { + CORBA::Object_var + objref = context.orb_->string_to_object (record.ref ().c_str ()); + bindings_map->bind ( record.id ().c_str (), + record.kind ().c_str (), + objref.in (), + ((TAO_NS_Persistence_Record::REMOTE_NCONTEXT == record.type ()) + ? CosNaming::ncontext // REMOTE_NCONTEXT + : CosNaming::nobject )); // OBJREF + } + } + context.storable_context_ = bindings_map; + context.context_ = context.storable_context_; + return 0; +} + +void +TAO_Storable_Naming_Context_ReaderWriter::write_header (const TAO_NS_Persistence_Header & header) +{ + stream_.rewind(); + stream_ << header.size(); + stream_ << header.destroyed(); + stream_.flush(); +} +void +TAO_Storable_Naming_Context_ReaderWriter::read_header (TAO_NS_Persistence_Header & header) +{ + unsigned int size; + int destroyed; + + stream_.rewind(); + + stream_ >> size; + header.size(size); + + stream_ >> destroyed; + header.destroyed(destroyed); +} + +void +TAO_Storable_Naming_Context_ReaderWriter::write_record (const TAO_NS_Persistence_Record & record) +{ + TAO_NS_Persistence_Record::Record_Type type = record.type(); + stream_ << type; + + stream_ << record.id(); + stream_ << record.kind(); + stream_ << record.ref(); + + stream_.flush(); +} + +void +TAO_Storable_Naming_Context_ReaderWriter::read_record (TAO_NS_Persistence_Record & record) +{ + int temp_type_in; + stream_ >> temp_type_in; + TAO_NS_Persistence_Record::Record_Type type = + (TAO_NS_Persistence_Record::Record_Type) temp_type_in; + record.type (type); + + ACE_CString record_id; + stream_ >> record_id; + record.id (record_id); + + ACE_CString record_kind; + stream_ >> record_kind; + record.kind (record_kind); + + ACE_CString record_ref; + stream_ >> record_ref; + record.ref (record_ref); +} + +void +TAO_Storable_Naming_Context_ReaderWriter::write_global (const TAO_NS_Persistence_Global & global) +{ + stream_.rewind(); + stream_ << global.counter(); + stream_.flush(); +} + +void +TAO_Storable_Naming_Context_ReaderWriter::read_global (TAO_NS_Persistence_Global + & global) +{ + unsigned int counter = 0; + + stream_.rewind(); + // We expect an exception to be thrown with EOF state if the file is empty. + try + { + stream_ >> counter; + } + catch (TAO::Storable_Read_Exception &ex) + { + if (ex.get_state() != TAO::Storable_Base::goodbit && + ex.get_state() != TAO::Storable_Base::eofbit) + throw CORBA::INTERNAL (); + } + + global.counter(counter); + +} + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_ReaderWriter.h b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_ReaderWriter.h new file mode 100644 index 00000000000..e0c06856ae3 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Naming/Storable_Naming_Context_ReaderWriter.h @@ -0,0 +1,64 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Storable_Naming_Context_ReaderWriter.h + * + * $Id$ + * + * @author Marina Spivak <marina@cs.wustl.edu> + * @author Byron Harris <harrisb@ociweb.com> + */ +//============================================================================= + +#ifndef TAO_STORABLE_NAMING_CONTEXT_READERWRITER_H +#define TAO_STORABLE_NAMING_CONTEXT_READERWRITER_H + +#include /**/ "ace/pre.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "tao/orbconf.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace TAO +{ + class Storable_Base; +} + +class TAO_Storable_Naming_Context; +class TAO_NS_Persistence_Record; +class TAO_NS_Persistence_Header; +class TAO_NS_Persistence_Global; + +class TAO_Storable_Naming_Context_ReaderWriter +{ +public: + + TAO_Storable_Naming_Context_ReaderWriter (TAO::Storable_Base & stream); + + int read (TAO_Storable_Naming_Context & context); + + void write (TAO_Storable_Naming_Context & context); + + void write_global (const TAO_NS_Persistence_Global & global); + void read_global (TAO_NS_Persistence_Global & global); + +private: + + void write_header (const TAO_NS_Persistence_Header & header); + void read_header (TAO_NS_Persistence_Header & header); + + void write_record (const TAO_NS_Persistence_Record & record); + void read_record (TAO_NS_Persistence_Record & record); + + TAO::Storable_Base &stream_; +}; + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* TAO_STORABLE_NAMING_CONTEXT_READERWRITER_H */ diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_Factory.cpp b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_Factory.cpp index fc10e0bb552..3ea3d1ee299 100644 --- a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_Factory.cpp +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_Factory.cpp @@ -7,24 +7,56 @@ * $Id$ * * @author Dale Wilson <wilson_d@ociweb.com> + * @author Byron Harris <harrisb@ociweb.com> */ //============================================================================= #include "orbsvcs/PortableGroup/PG_Group_Factory.h" #include "orbsvcs/PortableGroup/PG_Property_Utils.h" +#include "orbsvcs/PortableGroup/PG_Group_List_Store.h" #include "orbsvcs/PortableGroup/PG_conf.h" #include "orbsvcs/PortableGroupC.h" #include "orbsvcs/PortableGroup/PG_Object_Group.h" +#include "orbsvcs/PortableGroup/PG_Object_Group_Storable.h" #include <orbsvcs/PortableGroup/PG_Utils.h> +#include "tao/Storable_Factory.h" + +#include <ace/SString.h> + TAO_BEGIN_VERSIONED_NAMESPACE_DECL +namespace +{ + // Find the elements in set1 that + // are missing in set2. + template <class T> + void + find_missing(const std::set<T> & set1, + const std::set<T> & set2, + std::set<T> & missing_in_2) + { + missing_in_2.clear(); + for (typename std::set<T>::const_iterator it = set1.begin(); + it != set1.end(); ++it) + { + if (set2.find(*it) == set2.end()) + { + missing_in_2.insert(*it); + } + } + } +} + TAO::PG_Group_Factory::PG_Group_Factory () - : orb_ (CORBA::ORB::_nil()) + : use_persistence_ (false) + , list_store_ (0) + , orb_ (CORBA::ORB::_nil()) , poa_ (PortableServer::POA::_nil()) , manipulator_ () - , domain_id_ ("default-domain") - + , domain_id_ (ACE_TEXT_ALWAYS_CHAR ("default-domain")) + , groups_read_ (false) + , storable_factory_ (0) { } @@ -38,6 +70,8 @@ TAO::PG_Group_Factory::~PG_Group_Factory (void) delete group; } this->group_map_.unbind_all (); + delete this->list_store_; + delete this->storable_factory_; } @@ -52,7 +86,9 @@ void TAO::PG_Group_Factory::init ( this->orb_ = CORBA::ORB::_duplicate(orb); this->poa_ = PortableServer::POA::_duplicate (poa); - this->factory_registry_ = PortableGroup::FactoryRegistry::_duplicate (factory_registry); + + this->factory_registry_ = + PortableGroup::FactoryRegistry::_duplicate (factory_registry); ACE_ASSERT (!CORBA::is_nil (this->orb_.in ())); @@ -72,11 +108,25 @@ TAO::PG_Object_Group * TAO::PG_Group_Factory::create_group ( // Create an empty group reference PortableGroup::ObjectGroupId group_id = 0; - PortableGroup::ObjectGroup_var empty_group = - this->manipulator_.create_object_group ( - type_id, - this->domain_id_, - group_id); + PortableGroup::ObjectGroup_var empty_group; + + if (this->use_persistence_) + { + group_id = this->list_store_->get_next_group_id (); + empty_group = + this->manipulator_.create_object_group_using_id ( + type_id, + this->domain_id_, + group_id); + } + else + { + empty_group = + this->manipulator_.create_object_group ( + type_id, + this->domain_id_, + group_id); + } // pick up the object group information as assigned by // ObjectGroupManager @@ -89,19 +139,37 @@ TAO::PG_Object_Group * TAO::PG_Group_Factory::create_group ( TAO::PG_Object_Group * objectGroup = 0; - ACE_NEW_THROW_EX ( - objectGroup, - TAO::PG_Object_Group ( - this->orb_.in (), - this->factory_registry_.in (), - this->manipulator_, - empty_group.in (), - tagged_component, - type_id, - the_criteria, - typeid_properties - ), - CORBA::NO_MEMORY()); + if (this->use_persistence_) + { + objectGroup = this->create_persistent_group ( + this->orb_.in (), + this->factory_registry_.in (), + this->manipulator_, + empty_group.in (), + tagged_component, + type_id, + the_criteria, + typeid_properties, + *storable_factory_); + + this->list_store_->add(group_id); + } + else + { + ACE_NEW_THROW_EX ( + objectGroup, + TAO::PG_Object_Group ( + this->orb_.in (), + this->factory_registry_.in (), + this->manipulator_, + empty_group.in (), + tagged_component, + type_id, + the_criteria, + typeid_properties + ), + CORBA::NO_MEMORY()); + } if (this->group_map_.bind (group_id, objectGroup) != 0) { @@ -111,7 +179,8 @@ TAO::PG_Object_Group * TAO::PG_Group_Factory::create_group ( return objectGroup; } -void TAO::PG_Group_Factory::delete_group (PortableGroup::ObjectGroup_ptr object_group) +void TAO::PG_Group_Factory::delete_group ( + PortableGroup::ObjectGroup_ptr object_group) { if (! destroy_group (object_group)) { @@ -120,7 +189,8 @@ void TAO::PG_Group_Factory::delete_group (PortableGroup::ObjectGroup_ptr object_ } -void TAO::PG_Group_Factory::delete_group (PortableGroup::ObjectGroupId group_id) +void TAO::PG_Group_Factory::delete_group ( + PortableGroup::ObjectGroupId group_id) { if (! destroy_group (group_id)) { @@ -134,17 +204,20 @@ int TAO::PG_Group_Factory::insert_group ( ::TAO::PG_Object_Group * group) return insert_group (group->get_object_group_id(), group); } -int TAO::PG_Group_Factory::insert_group (PortableGroup::ObjectGroupId group_id, ::TAO::PG_Object_Group * group) +int TAO::PG_Group_Factory::insert_group (PortableGroup::ObjectGroupId group_id, + ::TAO::PG_Object_Group * group) { - return (this->group_map_.bind (group_id, group) == 0); + return (this->get_group_map ().bind (group_id, group) == 0); } -int TAO::PG_Group_Factory::find_group (PortableGroup::ObjectGroupId group_id, ::TAO::PG_Object_Group *& group) const +int TAO::PG_Group_Factory::find_group (PortableGroup::ObjectGroupId group_id, + ::TAO::PG_Object_Group *& group) { - return (this->group_map_.find (group_id , group) == 0); + return (this->get_group_map ().find (group_id , group) == 0); } -int TAO::PG_Group_Factory::find_group (PortableGroup::ObjectGroup_ptr object_group, ::TAO::PG_Object_Group *& group) const +int TAO::PG_Group_Factory::find_group (PortableGroup::ObjectGroup_ptr object_group, + ::TAO::PG_Object_Group *& group) { int result = 0; PortableGroup::TagGroupTaggedComponent tc; @@ -155,13 +228,49 @@ int TAO::PG_Group_Factory::find_group (PortableGroup::ObjectGroup_ptr object_gro return result; } +int TAO::PG_Group_Factory::find_group_with_name (const char* target_group_name, + TAO::PG_Object_Group *& group_target) +{ + int result = 0; + + // Search through the group map for the group with that property + Group_Map & group_map = this->get_group_map (); + for (Group_Map_Iterator it = group_map.begin (); + it != group_map.end (); + ++it) + { + TAO::PG_Object_Group * a_group = (*it).int_id_; + // If the group has the group name in the property + // + const char* a_group_name = a_group->get_name (); + if (a_group_name != 0 && + ACE_OS::strcmp (target_group_name, + a_group_name) == 0) + { // This is the group we were looking for + group_target = a_group; + result = 1; + break; + } + } + return result; +} + int TAO::PG_Group_Factory::destroy_group (PortableGroup::ObjectGroupId group_id) { ::TAO::PG_Object_Group * group = 0; - int result = (this->group_map_.unbind (group_id, group) == 0); + int result = (this->get_group_map ().unbind (group_id, group) == 0); if (result) { - delete group; + if (this->use_persistence_) + { + PG_Object_Group_Storable *og = + dynamic_cast<PG_Object_Group_Storable *> (group); + og->set_destroyed (true); + result = (this->list_store_->remove (group->get_object_group_id ()) + == 0); + } + if (result) + delete group; } return result; } @@ -179,7 +288,8 @@ PortableGroup::ObjectGroups * TAO::PG_Group_Factory::groups_at_location ( const PortableGroup::Location & the_location) { - size_t upper_limit = this->group_map_.current_size (); + Group_Map & group_map = this->get_group_map (); + size_t upper_limit = group_map.current_size (); PortableGroup::ObjectGroups * result = 0; ACE_NEW_THROW_EX ( result, @@ -189,8 +299,8 @@ TAO::PG_Group_Factory::groups_at_location ( result->length(upper_limit); size_t group_count = 0; - for (Group_Map_Iterator it = this->group_map_.begin (); - it != this->group_map_.end (); + for (Group_Map_Iterator it = group_map.begin (); + it != group_map.end (); ++it) { TAO::PG_Object_Group * group = (*it).int_id_; @@ -204,4 +314,171 @@ TAO::PG_Group_Factory::groups_at_location ( return result; } +PortableGroup::ObjectGroups * +TAO::PG_Group_Factory::all_groups (void) +{ + Group_Map & group_map = this->get_group_map (); + size_t upper_limit = group_map.current_size (); + PortableGroup::ObjectGroups * result = 0; + ACE_NEW_THROW_EX ( + result, + PortableGroup::ObjectGroups (upper_limit), + CORBA::NO_MEMORY()); + + result->length(upper_limit); + + size_t group_count = 0; + for (Group_Map_Iterator it = group_map.begin (); + it != group_map.end (); + ++it) + { + TAO::PG_Object_Group * group = (*it).int_id_; + (*result)[group_count] = CORBA::Object::_duplicate(group->reference ()); + ++group_count; + } + result->length (group_count); + return result; +} + +void +TAO::PG_Group_Factory::set_object_group_storable_factory ( + TAO::Storable_Factory * factory) +{ + this->use_persistence_ = true; + this->storable_factory_ = factory; + ACE_NEW_THROW_EX (this->list_store_, + TAO::PG_Group_List_Store (*this->storable_factory_), + CORBA::NO_MEMORY ()); + +} + +TAO::PG_Group_Factory::Group_Map & +TAO::PG_Group_Factory::get_group_map () +{ + if (this->use_persistence_) + { + // List of groups in persistent store may + // have changed since group_map_ was last + // updated. + + if (!this->groups_read_ || this->list_store_->list_obsolete ()) + { + // Extract IDs from group_map_ to set for comparison with IDs in persistent store + // This is to avoid having to repopulate the map from scratch. + PG_Group_List_Store::Group_Ids map_ids; + for (Group_Map_Iterator it = group_map_.begin (); + it != group_map_.end (); ++it) + { + map_ids.insert (it->key ()); + } + + // Get the latest groups from persistent store + const PG_Group_List_Store::Group_Ids & persistent_ids = + list_store_->get_group_ids (); + + // Find groups added since map was last updated + PG_Group_List_Store::Group_Ids groups_added; + find_missing (persistent_ids, map_ids, groups_added); + + // Find groups removed since map was last updated + PG_Group_List_Store::Group_Ids groups_removed; + find_missing (map_ids, persistent_ids, groups_removed); + + // Bind added groups + for (PG_Group_List_Store::Group_Id_Const_Iterator it = groups_added.begin (); + it != groups_added.end (); ++it) + { + PortableGroup::ObjectGroupId group_id = *it; + TAO::PG_Object_Group * objectGroup = 0; + objectGroup = this->restore_persistent_group ( + group_id, + this->orb_.in (), + this->factory_registry_.in (), + this->manipulator_, + *storable_factory_); + + if (this->group_map_.bind (group_id, objectGroup) != 0) + { + delete objectGroup; + throw PortableGroup::ObjectNotCreated (); + } + } + + // Unbind removed groups + for (PG_Group_List_Store::Group_Id_Const_Iterator it = groups_removed.begin (); + it != groups_removed.end (); ++it) + { + PortableGroup::ObjectGroupId group_id = *it; + PG_Object_Group * group = 0; + int result = (this->get_group_map ().unbind (group_id, group) == 0); + if (result) + { + delete group; + } + else + throw PortableGroup::ObjectGroupNotFound (); + } + + this->groups_read_ = true; + + } + + } + + return group_map_; +} + +TAO::PG_Object_Group_Storable * +TAO::PG_Group_Factory::create_persistent_group ( + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + CORBA::Object_ptr empty_group, + const PortableGroup::TagGroupTaggedComponent & tagged_component, + const char * type_id, + const PortableGroup::Criteria & the_criteria, + TAO::PG_Property_Set * type_properties, + TAO::Storable_Factory & storable_factory) +{ + TAO::PG_Object_Group_Storable * objectGroup = 0; + ACE_NEW_THROW_EX ( + objectGroup, + TAO::PG_Object_Group_Storable ( + orb, + factory_registry, + manipulator, + empty_group, + tagged_component, + type_id, + the_criteria, + type_properties, + storable_factory + ), + CORBA::NO_MEMORY()); + return objectGroup; +} + +TAO::PG_Object_Group_Storable * +TAO::PG_Group_Factory::restore_persistent_group ( + PortableGroup::ObjectGroupId group_id, + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + TAO::Storable_Factory & storable_factory) +{ + TAO::PG_Object_Group_Storable * objectGroup = 0; + ACE_NEW_THROW_EX ( + objectGroup, + TAO::PG_Object_Group_Storable ( + group_id, + orb, + factory_registry, + manipulator, + storable_factory + ), + CORBA::NO_MEMORY()); + return objectGroup; +} + + TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_Factory.h b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_Factory.h index 950513257e7..540d2bcd3b8 100644 --- a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_Factory.h +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_Factory.h @@ -7,6 +7,7 @@ * $Id$ * * @author Dale Wilson <wilson_d@ociweb.com> + * @author Byron Harris <harrisb@ociweb.com> */ //============================================================================= @@ -22,7 +23,6 @@ #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "orbsvcs/PortableGroup/PG_Object_Group_Manipulator.h" - #include "orbsvcs/PortableGroupC.h" #include "tao/PortableServer/PortableServer.h" @@ -34,11 +34,14 @@ TAO_BEGIN_VERSIONED_NAMESPACE_DECL ////////////////// -// Forward reference +// Forward references namespace TAO { class PG_Property_Set; -} // namespace TAO_PG + class PG_Group_List_Store; + class PG_Object_Group_Storable; + class Storable_Factory; +} namespace TAO { @@ -53,14 +56,16 @@ namespace TAO { //////////////////////////////////////////////////////////// // typedef private implementation classes - typedef ACE_Hash_Map_Manager_Ex< + typedef ACE_Hash_Map_Manager_Ex < PortableGroup::ObjectGroupId, ::TAO::PG_Object_Group *, ACE_Hash<ACE_UINT64>, ACE_Equal_To<ACE_UINT64>, TAO_SYNCH_MUTEX> Group_Map; - typedef ACE_Hash_Map_Entry <PortableGroup::ObjectGroupId, ::TAO::PG_Object_Group *> Group_Map_Entry; + typedef ACE_Hash_Map_Entry < + PortableGroup::ObjectGroupId, + ::TAO::PG_Object_Group *> Group_Map_Entry; typedef ACE_Hash_Map_Iterator_Ex < PortableGroup::ObjectGroupId, @@ -75,7 +80,7 @@ namespace TAO PG_Group_Factory (); /// Destructor. - ~PG_Group_Factory (); + virtual ~PG_Group_Factory (); void init ( CORBA::ORB_ptr orb, @@ -98,6 +103,11 @@ namespace TAO groups_at_location ( const PortableGroup::Location & the_location); + /** + * return all groups in the factory + */ + PortableGroup::ObjectGroups * + all_groups (void); /** @@ -105,26 +115,40 @@ namespace TAO * note: uses group id extracted from group object * @return bool true if insertion successful */ - int insert_group ( ::TAO::PG_Object_Group * group); + int insert_group (::TAO::PG_Object_Group * group); /** * insert group. Take ownership * @return bool true if insertion successful */ - int insert_group (PortableGroup::ObjectGroupId group_id, ::TAO::PG_Object_Group * group); + int insert_group ( + PortableGroup::ObjectGroupId group_id, + ::TAO::PG_Object_Group * group); /** * find group * @return bool true if found */ - int find_group (PortableGroup::ObjectGroupId group_id, ::TAO::PG_Object_Group *& group) const; + int find_group ( + PortableGroup::ObjectGroupId group_id, + ::TAO::PG_Object_Group *& group); /** * find group * note: uses group id extracted from object_group * @return bool true if found */ - int find_group (PortableGroup::ObjectGroup_ptr object_group, ::TAO::PG_Object_Group *& group) const; + int find_group ( + PortableGroup::ObjectGroup_ptr object_group, + ::TAO::PG_Object_Group *& group); + + /** + * find group with the property with the designated value + * @return bool true if found + */ + int find_group_with_name ( + const char* group_name, + ::TAO::PG_Object_Group *& group); /** * remove group from map and delete it. @@ -139,7 +163,42 @@ namespace TAO */ int destroy_group (PortableGroup::ObjectGroup_ptr object_group); - private: + /** + * persist internal state to file for fault tolerant purposes. + */ + void set_object_group_storable_factory (TAO::Storable_Factory * factory); + + protected: + + /** + * Factory function to create a storable object object from + * scratch. + */ + virtual PG_Object_Group_Storable * create_persistent_group ( + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + CORBA::Object_ptr empty_group, + const PortableGroup::TagGroupTaggedComponent & tagged_component, + const char * type_id, + const PortableGroup::Criteria & the_criteria, + TAO::PG_Property_Set * type_properties, + TAO::Storable_Factory & storable_factory); + + /** + * Factory function to restore an object group from + * persistent store. + */ + virtual PG_Object_Group_Storable * restore_persistent_group ( + PortableGroup::ObjectGroupId group_id, + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + TAO::Storable_Factory & storable_factory); + + bool use_persistence_; + + PG_Group_List_Store * list_store_; private: @@ -155,8 +214,19 @@ namespace TAO const char * domain_id_; + /** + * If persistence is being used, update the map as + * necessary based on what's in the group list store. + */ + Group_Map & get_group_map (); + Group_Map group_map_; + ///// Support for object group persistent ///// + + // Lazily read groups from store + bool groups_read_; + Storable_Factory * storable_factory_; }; } // namespace TAO diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_List_Store.cpp b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_List_Store.cpp new file mode 100644 index 00000000000..97541e4c009 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_List_Store.cpp @@ -0,0 +1,289 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file PG_Group_List_Store.cpp + * + * $Id$ + * + * @author Byron Harris <harrisb@ociweb.com> + */ +//============================================================================= + + +#include "orbsvcs/PortableGroup/PG_Group_List_Store.h" + +#include "tao/Storable_Base.h" +#include "tao/Storable_Factory.h" +#include "tao/Storable_File_Guard.h" + +#include <algorithm> + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace TAO +{ + class PG_Group_List_Store_File_Guard : public TAO::Storable_File_Guard + { + public: + PG_Group_List_Store_File_Guard (PG_Group_List_Store & list_store, + Method_Type method_type); + + ~PG_Group_List_Store_File_Guard (); + + virtual void set_object_last_changed (const time_t & time); + + virtual time_t get_object_last_changed (); + + virtual bool object_obsolete (); + + virtual void mark_object_current (); + + virtual void load_from_stream (); + + virtual bool is_loaded_from_stream (); + + virtual TAO::Storable_Base * create_stream (const char * mode); + +private: + + PG_Group_List_Store & list_store_; + }; +} + +TAO::PG_Group_List_Store_File_Guard::PG_Group_List_Store_File_Guard ( + PG_Group_List_Store & list_store, Method_Type method_type) + : TAO::Storable_File_Guard(true), + list_store_(list_store) +{ + try + { + this->init (method_type); + } + catch (const TAO::Storable_Read_Exception &) + { + throw CORBA::INTERNAL (); + } +} + +TAO::PG_Group_List_Store_File_Guard::~PG_Group_List_Store_File_Guard () +{ + this->release (); +} + +void +TAO::PG_Group_List_Store_File_Guard::set_object_last_changed ( + const time_t & time) +{ + list_store_.last_changed_ = time; +} + +time_t +TAO::PG_Group_List_Store_File_Guard::get_object_last_changed () +{ + return list_store_.last_changed_; +} + +bool +TAO::PG_Group_List_Store_File_Guard::object_obsolete () +{ + return list_store_.is_obsolete (fl_->last_changed ()); +} + +void +TAO::PG_Group_List_Store_File_Guard::mark_object_current () +{ + // Reset the stale flag + list_store_.stale(false); + // Set the last update time to the file last update time + this->set_object_last_changed (fl_->last_changed ()); +} + +void +TAO::PG_Group_List_Store_File_Guard::load_from_stream () +{ + list_store_.read (this->peer ()); + list_store_.loaded_from_stream_ = true; + this->peer ().rewind (); +} + +bool +TAO::PG_Group_List_Store_File_Guard::is_loaded_from_stream () +{ + return list_store_.loaded_from_stream_; +} + +TAO::Storable_Base * +TAO::PG_Group_List_Store_File_Guard::create_stream (const char * mode) +{ + return list_store_.create_stream (mode); +} + +typedef TAO::PG_Group_List_Store_File_Guard File_Guard; + +// Make shortcut to get to Method_Type enums +typedef TAO::Storable_File_Guard SFG; + +TAO::PG_Group_List_Store::PG_Group_List_Store ( + Storable_Factory & storable_factory) + : next_group_id_ (0) + , storable_factory_ (storable_factory) + , loaded_from_stream_ (false) + , last_changed_ (0) + , stale_ (false) +{ + // Create a temporary stream simply to check if a readable + // version already exists. + bool stream_exists = false; + { + ACE_Auto_Ptr<TAO::Storable_Base> stream ( + this->create_stream (ACE_TEXT_ALWAYS_CHAR ("r"))); + + if (stream->exists ()) + stream_exists = true; + } + + if (stream_exists) + { + File_Guard fg(*this, SFG::CREATE_WITH_FILE); + } + else + { + File_Guard fg(*this, SFG::CREATE_WITHOUT_FILE); + this->write (fg.peer ()); + } +} + +TAO::PG_Group_List_Store::~PG_Group_List_Store () +{ +} + +PortableGroup::ObjectGroupId +TAO::PG_Group_List_Store::get_next_group_id () +{ + File_Guard fg(*this, SFG::ACCESSOR); + PortableGroup::ObjectGroupId next_id = this->next_group_id_; + ++this->next_group_id_; + this->write (fg.peer ()); + return next_id; +} + +int +TAO::PG_Group_List_Store::add (PortableGroup::ObjectGroupId id) +{ + File_Guard fg(*this, SFG::MUTATOR); + Group_Id_Const_Iterator it = std::find (this->group_ids_.begin (), + this->group_ids_.end (), + id); + if (it != this->group_ids_.end()) + return -1; + this->group_ids_.insert (id); + this->write (fg.peer ()); + return 0; +} + +int +TAO::PG_Group_List_Store::remove (PortableGroup::ObjectGroupId id) +{ + File_Guard fg(*this, SFG::MUTATOR); + Group_Id_Iterator it = std::find (this->group_ids_.begin (), + this->group_ids_.end (), + id); + if (it == this->group_ids_.end ()) + return -1; + this->group_ids_.erase (it); + this->write (fg.peer ()); + return 0; +} + +TAO::PG_Group_List_Store::Group_Ids & +TAO::PG_Group_List_Store::get_group_ids () +{ + File_Guard fg(*this, SFG::ACCESSOR); + return group_ids_; +} + +void +TAO::PG_Group_List_Store::read (TAO::Storable_Base & stream) +{ + group_ids_.clear (); + + stream.rewind (); + + unsigned int next_group_id; + stream >> next_group_id; + this->next_group_id_ = next_group_id; + + int size; + stream >> size; + + // TODO: Look at adding streaming of unsigned long long + // PortableGroup::ObjectGroupId group_id; + int group_id; + for (int i = 0; i < size; ++i) + { + stream >> group_id; + group_ids_.insert (group_id); + } +} + +void +TAO::PG_Group_List_Store::write (TAO::Storable_Base & stream) +{ + stream.rewind (); + + unsigned int next_group_id = static_cast<unsigned int> (this->next_group_id_); + stream << next_group_id; + + int size = group_ids_.size (); + stream << size; + for (Group_Id_Const_Iterator it = group_ids_.begin (); + it != group_ids_.end (); ++it) + { + int group_id = static_cast<int> (*it); + stream << group_id; + } + + stream.flush (); +} + +TAO::Storable_Base * +TAO::PG_Group_List_Store::create_stream (const char * mode) +{ + return this->storable_factory_.create_stream ( + ACE_TEXT_ALWAYS_CHAR ("ObjectGroup_global"), mode); +} + +bool +TAO::PG_Group_List_Store::list_obsolete () +{ + // TODO: Upate if obsolete flag is set based on CORBA call. + ACE_Auto_Ptr<TAO::Storable_Base> stream (this->create_stream ("r")); + if (!stream->exists ()) + throw CORBA::INTERNAL (); + stream->open (); + return this->is_obsolete (stream->last_changed ()); +} + +bool +TAO::PG_Group_List_Store::is_obsolete (time_t stored_time) +{ + return + (!this->loaded_from_stream_) || + this->stale () || + (stored_time > this->last_changed_); +} + +void +TAO::PG_Group_List_Store::stale (bool is_stale) +{ + this->stale_ = is_stale; +} + +bool +TAO::PG_Group_List_Store::stale () +{ + return this->stale_; +} + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_List_Store.h b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_List_Store.h new file mode 100644 index 00000000000..8801ec6598d --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Group_List_Store.h @@ -0,0 +1,119 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file PG_Group_List_Store.h + * + * $Id$ + * + * @author Byron Harris <harrisb@ociweb.com> + */ +//============================================================================= + +#ifndef PG_GROUP_LIST_STORE_H +#define PG_GROUP_LIST_STORE_H + +#include /**/ "ace/pre.h" + +#include "orbsvcs/PortableGroup/portablegroup_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "orbsvcs/PortableGroupC.h" + +#include <set> + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace TAO +{ + class Storable_Base; + class Storable_Factory; +} + +namespace TAO +{ + /** + * @class PG_Group_List_Store + * Persists a list of object groups that are themselves persisted. + * All creation and deletion of persistent object groups should + * result in the list store being updated. + * This is done to support multiple group factories using the same + * persistent object groups. + * @see PG_Object_Group_Storable + */ + class TAO_PortableGroup_Export PG_Group_List_Store + { + public: + PG_Group_List_Store (Storable_Factory & storable_factory); + + ~PG_Group_List_Store (); + + /** + * Return a group ID that can be used for creating a new object group. + */ + PortableGroup::ObjectGroupId get_next_group_id (); + + int add (PortableGroup::ObjectGroupId id); + + int remove (PortableGroup::ObjectGroupId id); + + typedef std::set<PortableGroup::ObjectGroupId> Group_Ids; + + typedef std::set<PortableGroup::ObjectGroupId>::iterator + Group_Id_Iterator; + + typedef std::set<PortableGroup::ObjectGroupId>::reverse_iterator + Group_Id_Revers_Iterator; + + typedef std::set<PortableGroup::ObjectGroupId>::const_iterator + Group_Id_Const_Iterator; + + Group_Ids & get_group_ids (); + + /** + * Make explicit that state is stale instead of relying only + * on persistent file time stamp. + */ + void stale (bool is_stale); + + bool stale (); + + /** + * Answer if the list is obsolete because the persistent store has been updated. + * Used by PG_Group_Factory to avoid having to compare IDs in group_map_ with + * the list contained here. + */ + bool list_obsolete (); + + private: + + Group_Ids group_ids_; + + /// Ensure ID is monotonically increasing even when groups gets + /// removed. + PortableGroup::ObjectGroupId next_group_id_; + + TAO::Storable_Base * create_stream (const char * mode); + + Storable_Factory & storable_factory_; + bool loaded_from_stream_; + time_t last_changed_; + bool stale_; + void read (TAO::Storable_Base & stream); + void write (TAO::Storable_Base & stream); + + bool is_obsolete (time_t stored_time); + + friend class PG_Group_List_Store_File_Guard; + + }; +} + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* PG_GROUP_LIST_STORE_H */ diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group.cpp b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group.cpp index f0ab31d5342..33ce7d67bb5 100644 --- a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group.cpp +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group.cpp @@ -6,6 +6,9 @@ #include "orbsvcs/PortableGroup/PG_Operators.h" // Borrow operator== on CosNaming::Name #include "orbsvcs/PortableGroup/PG_Utils.h" +#include "tao/MProfile.h" +#include "tao/Profile.h" +#include "tao/Stub.h" #include "tao/debug.h" #include "ace/Get_Opt.h" @@ -61,11 +64,13 @@ TAO::PG_Object_Group::PG_Object_Group ( , orb_ (CORBA::ORB::_duplicate (orb)) , factory_registry_ (PortableGroup::FactoryRegistry::_duplicate (factory_registry)) , manipulator_ (manipulator) + , distribute_ (1) , empty_ (1) , role_ (type_id) , type_id_ (CORBA::string_dup (type_id)) , tagged_component_ (tagged_component) , reference_ (CORBA::Object::_duplicate(empty_group)) + , group_name_ (0) , members_ () , primary_location_(0) , properties_ (the_criteria, type_properties) @@ -75,16 +80,35 @@ TAO::PG_Object_Group::PG_Object_Group ( { } +TAO::PG_Object_Group::PG_Object_Group ( + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator) + : internals_() + , orb_ (CORBA::ORB::_duplicate (orb)) + , factory_registry_ (PortableGroup::FactoryRegistry::_duplicate (factory_registry)) + , manipulator_ (manipulator) + , distribute_ (1) + , empty_ (1) + , role_ ("") + , type_id_ () + , tagged_component_ () + , reference_ (CORBA::Object::_nil ()) + , group_name_ (0) + , members_ () + , primary_location_(0) + , properties_ () + , initial_number_members_ (0) + , minimum_number_members_ (0) + , group_specific_factories_ () +{ +} + TAO::PG_Object_Group::~PG_Object_Group (void) { - for (MemberMap_Iterator it = this->members_.begin(); - it != this->members_.end(); - ++it) - { - MemberInfo * member = (*it).int_id_; - delete member; - } - this->members_.unbind_all (); + CORBA::string_free (this->group_name_); + + this->clear_members_map (); } #if 0 // may want this again someday @@ -127,7 +151,7 @@ TAO::PG_Object_Group::get_group_specific_factories ( } const PortableGroup::Location & -TAO::PG_Object_Group::get_primary_location (void) const +TAO::PG_Object_Group::get_primary_location (void) { ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, @@ -192,11 +216,55 @@ TAO::PG_Object_Group::add_member (const PortableGroup::Location & the_location, // IORs, not IOGRs to send new IOGRs out // to replicas. + // Verify that the member is not using V1.0 profiles + // since IIOP V1.0 does not support tagged components + const TAO_MProfile &member_profiles = + member->_stubobj ()->base_profiles (); + CORBA::ULong member_profile_count = + member_profiles.profile_count (); + if (member_profile_count > 0) + { + const TAO_GIOP_Message_Version & version = + member_profiles.get_profile (0)->version (); + if (version.major_version () == 1 && + version.minor_version () == 0) + { + if (TAO_debug_level > 3) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%T %n (%P|%t) - ") + ACE_TEXT ("Can't add member because first profile ") + ACE_TEXT ("is IIOP version 1.0, which does not ") + ACE_TEXT ("support tagged components.\n") + )); + } + throw PortableGroup::ObjectNotAdded (); + } + } + CORBA::String_var member_ior_string = orb_->object_to_string (member); - PortableGroup::ObjectGroup_var new_reference = - add_member_to_iogr (member); + PortableGroup::ObjectGroup_var new_reference; + try { + new_reference = + this->add_member_to_iogr (member); + } + catch (const TAO_IOP::Duplicate&) + { + throw PortableGroup::MemberAlreadyPresent (); + } + catch (const TAO_IOP::Invalid_IOR&) + { + throw PortableGroup::ObjectNotAdded (); + } + catch (...) + { + throw; + } + + if (CORBA::is_nil (new_reference.in ())) + throw PortableGroup::ObjectNotAdded (); // Convert new member back to a (non group) ior. CORBA::Object_var member_ior = @@ -216,20 +284,21 @@ TAO::PG_Object_Group::add_member (const PortableGroup::Location & the_location, this->reference_ = new_reference; // note var-to-var assignment does // a duplicate + if (this->increment_version ()) { this->distribute_iogr (); } else - { + { // Issue with incrementing the version throw PortableGroup::ObjectNotAdded (); } if (TAO_debug_level > 6) - { - ACE_DEBUG ((LM_DEBUG, - ACE_TEXT("PG (%P|%t) exit Object_Group add_member\n"))); - } + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT("PG (%P|%t) exit Object_Group add_member\n"))); + } } int @@ -247,8 +316,8 @@ TAO::PG_Object_Group::set_primary_member ( { int cleared = 0; this->primary_location_ = the_location; - for (MemberMap_Iterator it = this->members_.begin(); - !cleared && it != this->members_.end(); + for (MemberMap_Iterator it = this->members_.begin (); + !cleared && it != this->members_.end (); ++it) { cleared = (*it).int_id_->is_primary_; @@ -314,7 +383,7 @@ TAO::PG_Object_Group::remove_member ( MemberInfo * info = 0; if (this->members_.unbind (the_location, info) == 0) { - if (this->members_.current_size() > 0) + if (this->members_.current_size () > 0) { this->reference_ = this->manipulator_.remove_profiles (this->reference_.in (), @@ -329,7 +398,7 @@ TAO::PG_Object_Group::remove_member ( if (the_location == this->primary_location_) { - this->primary_location_.length(0); + this->primary_location_.length (0); } if (this->increment_version ()) @@ -343,8 +412,8 @@ TAO::PG_Object_Group::remove_member ( if (TAO_debug_level > 6) { ACE_DEBUG ((LM_DEBUG, - "TAO-PG (%P|%t) - " - "remove_member throwing MemberNotFound.\n" + ACE_TEXT ("TAO-PG (%P|%t) - ") + ACE_TEXT ("remove_member throwing MemberNotFound.\n") )); } throw PortableGroup::MemberNotFound(); @@ -425,6 +494,10 @@ TAO::PG_Object_Group::increment_version (void) void TAO::PG_Object_Group::distribute_iogr (void) { + // Check if the object group is configured to distribute + if (!this->distribute_) + return; + // assume internals is locked CORBA::String_var iogr = this->orb_->object_to_string (this->reference_.in()); @@ -509,6 +582,7 @@ TAO::PG_Object_Group::locations_of_members (void) const PortableGroup::Location & location = (*it).ext_id_; PortableGroup::Location & out = (*result)[pos]; out = location; + ++pos; } return result; } @@ -795,5 +869,39 @@ TAO::PG_Object_Group::has_member_at (const PortableGroup::Location & location) return (0 == this->members_.find (location)); } +void +TAO::PG_Object_Group::distribute (int value) +{ + this->distribute_ = value; +} + +void +TAO::PG_Object_Group::set_name (const char* group_name) +{ + if (group_name_ != 0) + CORBA::string_free (group_name_); + + group_name_ = CORBA::string_dup (group_name); +} + +const char* +TAO::PG_Object_Group::get_name (void) +{ + return group_name_; +} + +void +TAO::PG_Object_Group::clear_members_map (void) +{ + for (MemberMap_Iterator it = this->members_.begin(); + it != this->members_.end(); + ++it) + { + MemberInfo * member = (*it).int_id_; + delete member; + } + this->members_.unbind_all (); +} + TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group.h b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group.h index f5b5328b68e..176e3ef2f7d 100644 --- a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group.h +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group.h @@ -57,6 +57,9 @@ namespace TAO */ class TAO_PortableGroup_Export PG_Object_Group { + + protected: + // Information about an object group member struct MemberInfo { @@ -73,7 +76,6 @@ namespace TAO /// Location where this member exists PortableGroup::Location location_; - /// TRUE if this is primary member CORBA::Boolean is_primary_; @@ -126,16 +128,24 @@ namespace TAO const PortableGroup::Criteria & the_criteria, TAO::PG_Property_Set * type_properties); + /** + * This constructor is to be used for initialization when + * reading the object group from a stream. + */ + PG_Object_Group ( + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator); /// Destructor - ~PG_Object_Group (); + virtual ~PG_Object_Group (); ///////////////// // public methods public: /// return a duplicated reference to this group (IOGR) - PortableGroup::ObjectGroup_ptr reference()const; + PortableGroup::ObjectGroup_ptr reference() const; /** * Note the caller receives a copy of the factoryinfos in the result argument. @@ -146,7 +156,7 @@ namespace TAO /** * get location of primary member */ - const PortableGroup::Location & get_primary_location() const; + virtual const PortableGroup::Location & get_primary_location(); /** * returns a duplicate @@ -186,14 +196,14 @@ namespace TAO /** * @@TODO DOC */ - PortableGroup::ObjectGroupId get_object_group_id () const; + virtual PortableGroup::ObjectGroupId get_object_group_id () const; /** * Add a new member to the group. * @param the_location the location for the new member * @param member the member to be added */ - void add_member ( + virtual void add_member ( const PortableGroup::Location & the_location, CORBA::Object_ptr member); @@ -204,21 +214,21 @@ namespace TAO * it returns a boolean result. A false return means caller should * throw FT::PrimaryNot_Set. */ - int set_primary_member ( + virtual int set_primary_member ( TAO_IOP::TAO_IOR_Property * prop, const PortableGroup::Location & the_location); /** * @@TODO DOC */ - void remove_member ( + virtual void remove_member ( const PortableGroup::Location & the_location); /** * @@TODO DOC */ - void create_member ( + virtual void create_member ( const PortableGroup::Location & the_location, const char * type_id, const PortableGroup::Criteria & the_criteria); @@ -226,30 +236,41 @@ namespace TAO /** * @@TODO DOC */ - PortableGroup::Locations * locations_of_members (void); + virtual PortableGroup::Locations * locations_of_members (void); /** * @@TODO DOC */ - CORBA::Object_ptr get_member_reference ( + virtual CORBA::Object_ptr get_member_reference ( const PortableGroup::Location & the_location); /** * @@TODO DOC */ - void initial_populate (void); + virtual void initial_populate (void); /** * @@TODO DOC */ - void minimum_populate (void); + virtual void minimum_populate (void); /** * @@TODO DOC */ - int has_member_at (const PortableGroup::Location & location ); + virtual int has_member_at (const PortableGroup::Location & location ); + + + /** + * Tell the object group that it should distribute updates to the object + * group state. + */ + virtual void distribute (int value); + + virtual void set_name (const char* group_name); + + virtual const char* get_name (void); ///////////////////////// // Implementation methods @@ -259,11 +280,13 @@ namespace TAO void distribute_iogr (void); - PortableGroup::ObjectGroup_ptr add_member_to_iogr(CORBA::Object_ptr member); + void create_members (size_t count); + protected: - void create_members (size_t count); + virtual PortableGroup::ObjectGroup_ptr add_member_to_iogr(CORBA::Object_ptr member); + void clear_members_map (void); ///////////////////////// // Forbidden methods @@ -290,19 +313,28 @@ namespace TAO */ mutable TAO_SYNCH_MUTEX internals_; + protected: CORBA::ORB_var orb_; + private: + /// Where to find the factories for replicas. PortableGroup::FactoryRegistry_var factory_registry_; + protected: // The object group manipulator TAO::PG_Object_Group_Manipulator & manipulator_; + /// boolean true if updates should be distributed + int distribute_; + /// boolean true if empty group int empty_; ACE_CString role_; + + PortableGroup::TypeId_var type_id_; /** @@ -325,6 +357,12 @@ namespace TAO */ PortableServer::ObjectId_var object_id_; + /** + * an optional attribute of the object group which is a string + * name that is assigned to the object group by the creator. + */ + char* group_name_; + // group members MemberMap members_; diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Manipulator.cpp b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Manipulator.cpp index 8e91038f8be..e8ccd41d89b 100644 --- a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Manipulator.cpp +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Manipulator.cpp @@ -61,7 +61,16 @@ TAO::PG_Object_Group_Manipulator::create_object_group ( PortableGroup::ObjectGroupId & group_id) { allocate_ogid(group_id); - PortableServer::ObjectId_var oid = convert_ogid_to_oid (group_id); + return this->create_object_group_using_id(type_id, domain_id, group_id); +} + +PortableGroup::ObjectGroup_ptr +TAO::PG_Object_Group_Manipulator::create_object_group_using_id( + const char * type_id, + const char * domain_id, + const PortableGroup::ObjectGroupId & group_id) +{ + PortableServer::ObjectId_var oid = convert_ogid_to_oid (group_id); // Create a reference for the ObjectGroup CORBA::Object_var object_group = diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Manipulator.h b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Manipulator.h index 91c37045d1f..35a2fbbd524 100644 --- a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Manipulator.h +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Manipulator.h @@ -63,6 +63,16 @@ namespace TAO const char * domain_id, PortableGroup::ObjectGroupId & group_id); + /** + * Create an empty object group using a specific ID. + * Note that this should not also be used with create_object_group () + * as the next object group ID to use will not necessarily be unique. + */ + PortableGroup::ObjectGroup_ptr create_object_group_using_id ( + const char * type_id, + const char * domain_id, + const PortableGroup::ObjectGroupId & group_id); + PortableGroup::ObjectGroup_ptr remove_profiles ( PortableGroup::ObjectGroup_ptr group, PortableGroup::ObjectGroup_ptr profile) const; diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Storable.cpp b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Storable.cpp new file mode 100644 index 00000000000..7a457881ca4 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Storable.cpp @@ -0,0 +1,571 @@ +// $Id$ + +#include "orbsvcs/PortableGroup/PG_Object_Group_Storable.h" + +#include "tao/Storable_File_Guard.h" +#include "tao/Storable_Factory.h" +#include "tao/CDR.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace +{ + template <typename T> + void read_cdr (TAO::Storable_Base & stream, T & corba_data) + { + int size; + stream >> size; + + char *tmp = 0; + ACE_NEW_THROW_EX (tmp, char [size], CORBA::NO_MEMORY ()); + ACE_Auto_Basic_Array_Ptr<char> buf (tmp); + stream.read (size, buf.get ()); + + TAO_InputCDR cdr (buf.get (), size); + cdr >> corba_data; + if (!cdr.good_bit ()) + { + stream.clear (); + throw CORBA::INTERNAL (); + } + } +} + +namespace TAO +{ + + class Object_Group_File_Guard : public TAO::Storable_File_Guard + { + public: + + Object_Group_File_Guard ( TAO::PG_Object_Group_Storable & object_group, + Method_Type method_type); + + ~Object_Group_File_Guard (); + + virtual void set_object_last_changed (const time_t & time); + + virtual time_t get_object_last_changed (); + + /// Check if the guarded object is current with the last + /// update which could have been performed independently of + /// the owner of this object. + virtual bool object_obsolete (); + + /// Mark the object as current with respect to the + /// file to which it was persisted. + virtual void mark_object_current (); + + virtual void load_from_stream (); + + virtual bool is_loaded_from_stream (); + + virtual TAO::Storable_Base * create_stream (const char * mode); + + private: + + TAO::PG_Object_Group_Storable & object_group_; + }; + +} + +TAO::Object_Group_File_Guard::Object_Group_File_Guard ( + TAO::PG_Object_Group_Storable & object_group, + Method_Type method_type) + : TAO::Storable_File_Guard(true) + , object_group_(object_group) +{ + try + { + this->init (method_type); + } + catch (const TAO::Storable_Read_Exception &) + { + throw CORBA::INTERNAL (); + } +} + +TAO::Object_Group_File_Guard::~Object_Group_File_Guard () +{ + this->release (); + + // Notify if persistent store was updated. + if (object_group_.write_occurred_) + object_group_.state_written (); +} + +void +TAO::Object_Group_File_Guard::set_object_last_changed (const time_t & time) +{ + object_group_.last_changed_ = time; +} + +time_t +TAO::Object_Group_File_Guard::get_object_last_changed () +{ + return object_group_.last_changed_; +} + +bool +TAO::Object_Group_File_Guard::object_obsolete () +{ + return object_group_.is_obsolete (fl_->last_changed ()); +} + +void +TAO::Object_Group_File_Guard::mark_object_current () +{ + object_group_.stale (false); + TAO::Storable_File_Guard::mark_object_current (); +} + +void +TAO::Object_Group_File_Guard::load_from_stream () +{ + object_group_.read (this->peer ()); + object_group_.loaded_from_stream_ = true; +} + +bool +TAO::Object_Group_File_Guard::is_loaded_from_stream () +{ + return object_group_.loaded_from_stream_; +} + +TAO::Storable_Base * +TAO::Object_Group_File_Guard::create_stream (const char * mode) +{ + return object_group_.create_stream (mode); +} + +// Make shortcut to get to Method_Type enums +typedef TAO::Storable_File_Guard SFG; + +TAO::PG_Object_Group_Storable::PG_Object_Group_Storable ( + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + CORBA::Object_ptr empty_group, + const PortableGroup::TagGroupTaggedComponent & tagged_component, + const char * type_id, + const PortableGroup::Criteria & the_criteria, + TAO::PG_Property_Set * type_properties, + TAO::Storable_Factory & storable_factory) + : PG_Object_Group(orb, + factory_registry, + manipulator, + empty_group, + tagged_component, + type_id, + the_criteria, + type_properties) + , group_previously_stored_(false) + , group_id_previously_stored_(0) + , storable_factory_ (storable_factory) + , last_changed_ (0) + , loaded_from_stream_ (false) + , destroyed_ (false) + , write_occurred_ (false) +{ + // Create a temporary stream simply to check if a readable + // version already exists. + bool stream_exists = false; + { + ACE_Auto_Ptr<TAO::Storable_Base> stream ( + this->create_stream (ACE_TEXT_ALWAYS_CHAR ("r"))); + + if (stream->exists ()) + stream_exists = true; + } + + if (stream_exists) + { + Object_Group_File_Guard fg (*this, SFG::CREATE_WITH_FILE); + } + else + { + Object_Group_File_Guard fg (*this, SFG::CREATE_WITHOUT_FILE); + this->write (fg.peer ()); + } +} + +TAO::PG_Object_Group_Storable::PG_Object_Group_Storable ( + PortableGroup::ObjectGroupId group_id, + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + TAO::Storable_Factory & storable_factory) + : PG_Object_Group(orb, + factory_registry, + manipulator) + , group_previously_stored_(true) + , group_id_previously_stored_(group_id) + , storable_factory_ (storable_factory) + , last_changed_ (0) + , loaded_from_stream_ (false) + , destroyed_ (false) + , write_occurred_ (false) +{ + // Create a temporary stream to simply to check if a readable + // version already exists. + bool stream_exists = false; + { + ACE_Auto_Ptr<TAO::Storable_Base> stream ( + this->create_stream (ACE_TEXT_ALWAYS_CHAR ("r"))); + + if (stream->exists ()) + stream_exists = true; + } + + if (stream_exists) + { + Object_Group_File_Guard fg (*this, SFG::ACCESSOR); + } + else + { + throw CORBA::INTERNAL (); + } +} + +TAO::PG_Object_Group_Storable::~PG_Object_Group_Storable (void) +{ + if (destroyed_) + { + ACE_Auto_Ptr<TAO::Storable_Base> stream ( + this->create_stream (ACE_TEXT_ALWAYS_CHAR ("r"))); + + if (stream->exists ()) + { + stream->remove (); + } + + } + +} + +void +TAO::PG_Object_Group_Storable::set_destroyed (bool destroyed) +{ + this->destroyed_ = destroyed; +} + +const PortableGroup::Location & +TAO::PG_Object_Group_Storable::get_primary_location (void) +{ + Object_Group_File_Guard fg (*this, SFG::ACCESSOR); + return TAO::PG_Object_Group::get_primary_location (); +} + + +void +TAO::PG_Object_Group_Storable::add_member ( + const PortableGroup::Location & the_location, + CORBA::Object_ptr member) +{ + Object_Group_File_Guard fg (*this, SFG::MUTATOR); + PG_Object_Group::add_member (the_location, member); + this->write (fg.peer ()); +} + +int +TAO::PG_Object_Group_Storable::set_primary_member ( + TAO_IOP::TAO_IOR_Property * prop, + const PortableGroup::Location & the_location) +{ + Object_Group_File_Guard fg (*this, SFG::MUTATOR); + int primary_member = PG_Object_Group::set_primary_member (prop, the_location); + this->write (fg.peer ()); + return primary_member; +} + +void +TAO::PG_Object_Group_Storable::remove_member ( + const PortableGroup::Location & the_location) +{ + Object_Group_File_Guard fg (*this, SFG::MUTATOR); + PG_Object_Group::remove_member (the_location); + this->write (fg.peer ()); +} + + +PortableGroup::Locations * +TAO::PG_Object_Group_Storable::locations_of_members (void) +{ + Object_Group_File_Guard fg (*this, SFG::ACCESSOR); + return PG_Object_Group::locations_of_members (); +} + +void +TAO::PG_Object_Group_Storable::create_member ( + const PortableGroup::Location & the_location, + const char * type_id, + const PortableGroup::Criteria & the_criteria) +{ + Object_Group_File_Guard fg (*this, SFG::MUTATOR); + PG_Object_Group::create_member (the_location, + type_id, + the_criteria); + this->write (fg.peer ()); +} + +void +TAO::PG_Object_Group_Storable::set_name (const char* group_name) +{ + Object_Group_File_Guard fg (*this, SFG::MUTATOR); + PG_Object_Group::set_name (group_name); + this->write (fg.peer ()); +} + +const char* +TAO::PG_Object_Group_Storable::get_name (void) +{ + Object_Group_File_Guard fg (*this, SFG::ACCESSOR); + return PG_Object_Group::get_name (); +} + +void +TAO::PG_Object_Group_Storable::initial_populate (void) +{ + Object_Group_File_Guard fg (*this, SFG::MUTATOR); + PG_Object_Group::initial_populate (); + this->write (fg.peer ()); +} + +void +TAO::PG_Object_Group_Storable::minimum_populate (void) +{ + Object_Group_File_Guard fg (*this, SFG::MUTATOR); + PG_Object_Group::minimum_populate (); + this->write (fg.peer ()); +} + +int +TAO::PG_Object_Group_Storable::has_member_at ( + const PortableGroup::Location & location) +{ + Object_Group_File_Guard fg (*this, SFG::ACCESSOR); + return PG_Object_Group::has_member_at (location); +} + +void +TAO::PG_Object_Group_Storable::distribute (int value) +{ + Object_Group_File_Guard fg (*this, SFG::MUTATOR); + PG_Object_Group::distribute (value); + this->write (fg.peer ()); +} + +CORBA::Object_ptr +TAO::PG_Object_Group_Storable::get_member_reference ( + const PortableGroup::Location & the_location) +{ + Object_Group_File_Guard fg (*this, SFG::ACCESSOR); + return PG_Object_Group::get_member_reference (the_location); +} + +PortableGroup::ObjectGroupId +TAO::PG_Object_Group_Storable::get_object_group_id () const +{ + if (this->group_previously_stored_) + return this->group_id_previously_stored_; + + return PG_Object_Group::get_object_group_id (); +} + +TAO::Storable_Base * +TAO::PG_Object_Group_Storable::create_stream (const char * mode) +{ + char file_name[BUFSIZ]; + // Although PortableGroup::ObjectGroupId is a typedef + // to long long int, make ID type explicit to avoid + // GNU C++ warning on sprintf statement. + long long int id = this->get_object_group_id (); + ACE_OS::sprintf (file_name, ACE_TEXT_ALWAYS_CHAR ("ObjectGroup_%lld"), id); + return this->storable_factory_.create_stream (file_name, mode); +} + +void +TAO::PG_Object_Group_Storable::read (TAO::Storable_Base & stream) +{ + stream.rewind (); + + ACE_CString group_name; + stream >> group_name; + + PG_Object_Group::set_name(group_name.c_str()); + + stream >> this->distribute_; + + stream >> this->role_; + + ///// primary_location_ ///// + read_cdr (stream, this->primary_location_); + + ///// reference_ ///// + ACE_CString reference_ior; + stream >> reference_ior; + this->reference_ = this->orb_->string_to_object (reference_ior.c_str ()); + + ///// tagged_component_ ///// + read_cdr (stream, this->tagged_component_); + + ///// type_id_ ///// + read_cdr(stream, this->type_id_); + + ///// properties_ ///// + PortableGroup::Criteria properties; + read_cdr (stream, properties); + PG_Object_Group::set_properties_dynamically (properties); + + ///// members_ ///// + int num_members; + stream >> num_members; + + this->clear_members_map (); + + for (int i = 0; i < num_members; ++i) + { + ///// location used as members_ key ///// + PortableGroup::Location the_location; + read_cdr (stream, the_location); + + ///// member ///// + ACE_CString member_ior; + stream >> member_ior; + CORBA::Object_var member = + this->orb_->string_to_object (member_ior.c_str ()); + if (CORBA::is_nil (member)) + throw CORBA::INV_OBJREF (); + + ///// location ///// + PortableGroup::Location location; + read_cdr (stream, location); + + ///// factory ///// + ACE_CString factory_ior; + stream >> factory_ior; + CORBA::Object_var obj = + this->orb_->string_to_object (factory_ior.c_str ()); + PortableGroup::GenericFactory_var factory = + PortableGroup::GenericFactory::_narrow (obj.in()); + + ///// factory_id (typedef of CORBA::Any) ///// + PortableGroup::GenericFactory::FactoryCreationId factory_id; + read_cdr (stream, factory_id); + + ///// is_primary ///// + int is_primary; + stream >> is_primary; + + MemberInfo * info = 0; + ACE_NEW_THROW_EX (info, MemberInfo(member.in (), + the_location, + factory, + factory_id), + CORBA::NO_MEMORY()); + + info->is_primary_ = is_primary; + + if (this->members_.bind (the_location, info) != 0) + { + throw CORBA::NO_MEMORY(); + } + } +} + +void +TAO::PG_Object_Group_Storable::write (TAO::Storable_Base & stream) +{ + stream.rewind (); + + ACE_CString group_name = PG_Object_Group::get_name (); + stream << group_name; + stream << this->distribute_; + stream << this->role_; + + TAO_OutputCDR primary_location_cdr; + primary_location_cdr << PG_Object_Group::get_primary_location (); + stream << primary_location_cdr; + + ACE_CString reference_ior = + this->orb_->object_to_string (this->reference_.in ()); + stream << reference_ior; + + TAO_OutputCDR tagged_component_cdr; + tagged_component_cdr << this->tagged_component_; + stream << tagged_component_cdr; + + TAO_OutputCDR type_id_cdr; + PortableGroup::TypeId_var type_id = PG_Object_Group::get_type_id (); + type_id_cdr << type_id; + stream << type_id_cdr; + + TAO_OutputCDR properties_cdr; + PortableGroup::Criteria properties; + this->properties_.export_properties (properties); + properties_cdr << properties; + stream << properties_cdr; + + ///// members_ ///// + int num_members = this->members_.current_size (); + stream << num_members; + for (MemberMap_Iterator it = this->members_.begin (); + it != this->members_.end (); + ++it) + { + PortableGroup::Location the_location = it->key (); + TAO_OutputCDR the_location_cdr; + the_location_cdr << the_location; + stream << the_location_cdr; + + MemberInfo * member = it->item (); + ACE_CString member_ior = + this->orb_->object_to_string (member->member_.in ()); + stream << member_ior; + + TAO_OutputCDR location_cdr; + location_cdr << member->location_; + stream << location_cdr; + + ACE_CString factory_ior = + this->orb_->object_to_string (member->factory_.in ()); + stream << factory_ior; + + TAO_OutputCDR factory_id_cdr; + factory_id_cdr << member->factory_id_; + stream << factory_id_cdr; + + stream << member->is_primary_; + } + stream.flush (); + this->write_occurred_ = true; +} + +void +TAO::PG_Object_Group_Storable::stale (bool is_stale) +{ + ACE_UNUSED_ARG (is_stale); + // Default implementation is no-op +} + +bool +TAO::PG_Object_Group_Storable::stale () +{ + // Default is to return false + return false; +} + +void +TAO::PG_Object_Group_Storable::state_written (void) +{ + // No-op. Overridden by derived class. +} + +bool +TAO::PG_Object_Group_Storable::is_obsolete (time_t stored_time) +{ + return (!this->loaded_from_stream_) || + stored_time > this->last_changed_; +} + +TAO_END_VERSIONED_NAMESPACE_DECL diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Storable.h b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Storable.h new file mode 100644 index 00000000000..56d86677624 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Object_Group_Storable.h @@ -0,0 +1,194 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file PG_Object_Group_Storable.h + * + * $Id$ + * + * Contains declaration for class PG_Object_Group_Storable. + * + * @author Byron Harris <harrisb@ociweb.com> + */ +//============================================================================= + +#ifndef TAO_PG_OBJECT_GROUP_STORABLE_H_ +#define TAO_PG_OBJECT_GROUP_STORABLE_H_ +#include /**/ "ace/pre.h" + +#include "orbsvcs/PortableGroup/portablegroup_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + + +///////////////////////////////// +// Includes needed by this header +#include "orbsvcs/PortableGroup/PG_Object_Group.h" + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +///////////////////// +// Forward references +namespace TAO +{ + class Storable_Factory; + class Storable_Base; +} + +//////////////// +// Class declarations +namespace TAO +{ + /** + * An object group whose state persists to a stream so that its state + * can be saved/retrieved between processes that use the group. + */ + class TAO_PortableGroup_Export PG_Object_Group_Storable + : public PG_Object_Group + { + + ///////////////////// + // Construct/Destruct + public: + + /** + * This constructor is suitable for creating an object group from + * scratch. + */ + PG_Object_Group_Storable ( + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + CORBA::Object_ptr empty_group, + const PortableGroup::TagGroupTaggedComponent & tagged_component, + const char * type_id, + const PortableGroup::Criteria & the_criteria, + TAO::PG_Property_Set * type_properties, + TAO::Storable_Factory & storable_factory); + + /** + * This constructor is suitable for creating an object group from + * persistent store. + */ + PG_Object_Group_Storable ( + PortableGroup::ObjectGroupId group_id, + CORBA::ORB_ptr orb, + PortableGroup::FactoryRegistry_ptr factory_registry, + TAO::PG_Object_Group_Manipulator & manipulator, + TAO::Storable_Factory & storable_factory); + + /// Destructor + ~PG_Object_Group_Storable (); + + ///////////////// + // public methods + + public: + + /** + * Indicate that this object group is to be permanently + * destroyed. During destruction the persistent store + * for this will then be removed. + * This is to distinguish between deletion from a process + * shutdown verses deletion from a destroy request. + */ + void set_destroyed (bool destroyed); + + /** + * Allow for replication persistence support by + * derived classes. + */ + virtual void stale (bool is_stale); + virtual bool stale (); + + virtual const PortableGroup::Location & get_primary_location (); + + virtual void add_member ( + const PortableGroup::Location & the_location, + CORBA::Object_ptr member); + + virtual int set_primary_member ( + TAO_IOP::TAO_IOR_Property * prop, + const PortableGroup::Location & the_location); + + virtual void remove_member ( + const PortableGroup::Location & the_location); + + virtual void create_member ( + const PortableGroup::Location & the_location, + const char * type_id, + const PortableGroup::Criteria & the_criteria); + + virtual PortableGroup::Locations * locations_of_members (void); + + virtual CORBA::Object_ptr get_member_reference ( + const PortableGroup::Location & the_location); + + virtual void initial_populate (void); + + virtual void minimum_populate (void); + + virtual int has_member_at (const PortableGroup::Location & location ); + + virtual void distribute (int value); + + virtual void set_name (const char* group_name); + + virtual const char* get_name (void); + + virtual PortableGroup::ObjectGroupId get_object_group_id () const; + + private: + + ///////////////////////// + // Forbidden methods + PG_Object_Group_Storable (); + PG_Object_Group_Storable (const PG_Object_Group_Storable & rhs); + PG_Object_Group_Storable & operator = (const PG_Object_Group_Storable & rhs); + + /// Indicate if instance of object group has been restored from store + bool group_previously_stored_; + PortableGroup::ObjectGroupId group_id_previously_stored_; + + TAO::Storable_Base * create_stream (const char * mode); + + void read (TAO::Storable_Base & stream); + + void write (TAO::Storable_Base & stream); + + TAO::Storable_Factory & storable_factory_; + time_t last_changed_; + + protected: + + bool loaded_from_stream_; + + bool destroyed_; + + /// To set when state written out. + bool write_occurred_; + + /** + * Signals that this context was updated. + */ + virtual void state_written (void); + + /** + * A callback invoked by the object group file guard + * to determine if this context is obsolete with respect to + * the peristent store. + */ + virtual bool is_obsolete (time_t stored_time); + + friend class Object_Group_File_Guard; + + }; +} // namespace TAO + +TAO_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif // TAO_PG_OBJECT_GROUP_STORABLE_H_ diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Property_Set.cpp b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Property_Set.cpp index 07739231579..ede4d544d03 100644 --- a/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Property_Set.cpp +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/PG_Property_Set.cpp @@ -149,24 +149,22 @@ void TAO::PG_Property_Set::set_property ( CORBA::NO_MEMORY ()); const PortableGroup::Value * replaced_value = 0; - if (0 == this->values_.rebind (name, value_copy, replaced_value)) - { - if (0 != replaced_value) - { + int rebind_result = this->values_.rebind (name, value_copy, replaced_value); + if (1 == rebind_result) + { // Existing value was replaced delete replaced_value; } - } - else - { - if (TAO_debug_level > 3) - { - ACE_ERROR ( (LM_ERROR, - "%n\n%T: Property_set: rebind failed.\n" - )); + else if (-1 == rebind_result) + { // Value was not rebound. + if (TAO_debug_level > 3) + { + ACE_ERROR ( (LM_ERROR, + "%n\n%T: Property_set: rebind failed.\n" + )); + } + // @@ should throw something here + throw CORBA::NO_MEMORY (); } - // @@ should throw something here - throw CORBA::NO_MEMORY (); - } } diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/UIPMC_Profile.cpp b/TAO/orbsvcs/orbsvcs/PortableGroup/UIPMC_Profile.cpp index fecf55c86b8..10a7057b444 100644 --- a/TAO/orbsvcs/orbsvcs/PortableGroup/UIPMC_Profile.cpp +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/UIPMC_Profile.cpp @@ -547,7 +547,7 @@ TAO_UIPMC_Profile::endpoint_count (void) const } char * -TAO_UIPMC_Profile::to_string (void) +TAO_UIPMC_Profile::to_string (void) const { // corbaloc:miop:1.0@1.0-group_id-1-1/host:port diff --git a/TAO/orbsvcs/orbsvcs/PortableGroup/UIPMC_Profile.h b/TAO/orbsvcs/orbsvcs/PortableGroup/UIPMC_Profile.h index 994af6d4274..7406a16b0d1 100644 --- a/TAO/orbsvcs/orbsvcs/PortableGroup/UIPMC_Profile.h +++ b/TAO/orbsvcs/orbsvcs/PortableGroup/UIPMC_Profile.h @@ -82,7 +82,7 @@ public: /// a useable decode_endpoints virtual int decode (TAO_InputCDR &cdr); virtual void parse_string (const char *string); - virtual char * to_string (void); + virtual char * to_string (void) const; virtual int encode_endpoints (void); virtual void encodeAddressInfo (TAO_OutputCDR &stream) const; virtual TAO_Endpoint *endpoint (void); diff --git a/TAO/orbsvcs/orbsvcs/cosnaming_serv_persistence.mpb b/TAO/orbsvcs/orbsvcs/cosnaming_serv_persistence.mpb index 1caf3ca3f1f..8318fbecd86 100644 --- a/TAO/orbsvcs/orbsvcs/cosnaming_serv_persistence.mpb +++ b/TAO/orbsvcs/orbsvcs/cosnaming_serv_persistence.mpb @@ -5,13 +5,15 @@ feature(!corba_e_micro) { Source_Files(ORBSVCS_COMPONENTS) { Naming { - Naming/Flat_File_Persistence.cpp Naming/Persistent_Context_Index.cpp Naming/Persistent_Entries.cpp Naming/Persistent_Naming_Context.cpp Naming/Storable.cpp Naming/Storable_Naming_Context.cpp Naming/Storable_Naming_Context_Activator.cpp + Naming/Storable_Naming_Context_ReaderWriter.cpp + Naming/Persistent_Naming_Context_Factory.cpp + Naming/Storable_Naming_Context_Factory.cpp } } } diff --git a/TAO/orbsvcs/tests/Bug_2777_Regression/run_test.pl b/TAO/orbsvcs/tests/Bug_2777_Regression/run_test.pl index 60fbbfbcf21..e6bfe97b362 100755 --- a/TAO/orbsvcs/tests/Bug_2777_Regression/run_test.pl +++ b/TAO/orbsvcs/tests/Bug_2777_Regression/run_test.pl @@ -17,36 +17,7 @@ foreach $i (@ARGV) { } } -my $exec_extn = ""; -if ($^O eq "MSWin32") { - $exec_extn = ".exe"; -} - -my @nslist_paths = (["../../../../bin", ""], - ["../../../bin", ""], - ["../../../../TAO/utils/nslist", ""]); -if (grep(($_ eq 'ARCH'), @PerlACE::ConfigList::Configs)) { - push @nslist_paths, ["../../../../bin/" . $PerlACE::Process::ExeSubDir, - "../../../../bin"]; -} - -my $nslist_path = ""; -for my $p (@nslist_paths) { - my $use_path = ($p->[1] eq "") ? $p->[0] : $p->[1]; - if (-e $p->[0] . '/tao_nslist') { - $nslist_path = $use_path . '/tao_nslist'; - last; - } - if ($exec_extn ne "" && -e $p->[0] . '/tao_nslist' . $exec_extn) { - $nslist_path = $use_path . '/tao_nslist'; - last; - } -} - -if ($nslist_path eq "") { - print STDERR "ERROR: tao_nslist utility not found.\n"; - exit 1; -} +my $nslist_path = "$ENV{ACE_ROOT}/bin/tao_nslist"; ## The two test targets will communicate over shared memory (SHMIOP) so they ## can't be 32-bit and 64-bit executables on the same host. diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/Basic.cpp b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/Basic.cpp new file mode 100644 index 00000000000..3f2061b3483 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/Basic.cpp @@ -0,0 +1,64 @@ +// $Id$ + +#include "Basic.h" + +Basic::Basic (CORBA::Object_ptr object_group, + FT_Naming::NamingManager_ptr lm, + CORBA::ORB_ptr orb, + const char *loc) + : object_group_name_ (ACE_TEXT_ALWAYS_CHAR ("BasicGroup")), + orb_ (CORBA::ORB::_duplicate (orb)) +{ + this->object_group_ = CORBA::Object::_duplicate (object_group); + this->nm_ = FT_Naming::NamingManager::_duplicate (lm); + this->location_ = CORBA::string_dup (loc); +} + +char * +Basic::get_string (void) +{ + return CORBA::string_dup (this->location_.in ()); +} + +void +Basic::remove_member (void) +{ + try + { + PortableGroup::Location location (1); + location.length (1); + location[0].id = CORBA::string_dup (this->location_.in ()); + this->nm_->remove_member (this->object_group_.in (), + location); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - Removed Member at Location <%s>\n"), + this->location_.in ())); + + } + catch (const PortableGroup::ObjectNotFound& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Caught exception in remove_member")); + throw CORBA::INTERNAL (); + } + catch (const PortableGroup::MemberNotFound& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Caught exception in remove_member")); + throw CORBA::INTERNAL (); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Exception caught while destroying member\n")); + } + +} + + +void +Basic::shutdown (void) +{ + this->orb_->shutdown (0); +} diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/Basic.h b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/Basic.h new file mode 100644 index 00000000000..1664eddc322 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/Basic.h @@ -0,0 +1,59 @@ +// -*- C++ -*- +// +// $Id$ + +#ifndef BASIC_H +#define BASIC_H + +#include "TestS.h" +#include "orbsvcs/FT_NamingManagerC.h" +#include "orbsvcs/PortableGroupC.h" + +#if defined (_MSC_VER) +# pragma warning(push) +# pragma warning (disable:4250) +#endif /* _MSC_VER */ + +class LB_Basic_Test; + +/// Implement the Test::Basic interface +class Basic + : public virtual POA_Test::Basic +{ +public: + /// Constructor + Basic (CORBA::Object_ptr object_group, + FT_Naming::NamingManager_ptr lm, + CORBA::ORB_ptr orb, + const char *loc); + + virtual char * get_string (void); + + virtual void shutdown (void); + + virtual void remove_member (void); + +private: + + const char* object_group_name_; + + /// Use an ORB reference to convert strings to objects and shutdown + /// the application. + CORBA::ORB_var orb_; + + /// Naming Manager Reference used to delete the member from the + /// object group. + FT_Naming::NamingManager_var nm_; + + /// location of the member + CORBA::String_var location_; + + /// Object Group reference. + CORBA::Object_var object_group_; +}; + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif /* _MSC_VER */ + +#endif /* BASIC_H */ diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/FaultTolerant.mpc b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/FaultTolerant.mpc new file mode 100644 index 00000000000..5a6f64227f4 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/FaultTolerant.mpc @@ -0,0 +1,32 @@ +// -*- MPC -*- +// $Id$ + +project(*Client) : ftnaming { + exename = client + + Source_Files { + client.cpp + } + +} + +project(*idl): taoidldefaults { + IDL_Files { + Test.idl + } + custom_only = 1 +} + +project(*server): ftnaming { + after += *idl + exename = server + Source_Files { + TestC.cpp + TestS.cpp + server.cpp + LB_server.cpp + Basic.cpp + } + IDL_Files { + } +} diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/LB_server.cpp b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/LB_server.cpp new file mode 100644 index 00000000000..ee4f5dd9ed9 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/LB_server.cpp @@ -0,0 +1,229 @@ +// $Id$ + +#include "LB_server.h" +#include "Basic.h" + +#include "TestC.h" +#include "ace/OS_NS_stdio.h" + +LB_server::LB_server (int argc, ACE_TCHAR **argv) + : argc_ (argc) + , argv_ (argv) + , ior_output_file_ (ACE_TEXT ("obj.ior")) +{ +} + +int +LB_server::destroy (void) +{ + try + { + this->naming_manager_->delete_object_group ( + ACE_TEXT_ALWAYS_CHAR ("BasicGroup")); + + //TODO: Does the FT_NamingManager need a destroy method? +// this->naming_manager_->destroy (1, 1); + + this->orb_->destroy (); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Exception caught while destroying LB_server\n")); + return -1; + } + return 0; + +} + +CORBA::ORB_ptr +LB_server::orb (void) +{ + return this->orb_.in (); +} + +CORBA::Object_ptr +LB_server::object_group (void) +{ + return this->object_group_.in (); +} + +FT_Naming::NamingManager_ptr +LB_server::naming_manager (void) +{ + return this->naming_manager_.in (); +} + +int +LB_server::write_ior_to_file (const char *ior) +{ + FILE *output_file = + ACE_OS::fopen (this->ior_output_file_, ACE_TEXT_ALWAYS_CHAR("w")); + + if (output_file == 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Cannot open output file for writing IOR:"))); + return -1; + } + + ACE_OS::fprintf (output_file, ACE_TEXT_ALWAYS_CHAR ("%s"), ior); + ACE_OS::fclose (output_file); + return 0; +} + +int +LB_server::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("o:")); + int c; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'o': + this->ior_output_file_ = get_opts.opt_arg (); + break; + case '?': + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("usage: %s ") + ACE_TEXT ("-o <iorfile>") + ACE_TEXT ("\n"), + argv [0]), + -1); + } + // Indicates successful parsing of the command line + return 0; +} + +int +LB_server::start_orb_and_poa (void) +{ + try + { + // Initialise the ORB. + this->orb_ = CORBA::ORB_init (this->argc_, this->argv_); + + CORBA::Object_var poa_object = + this->orb_->resolve_initial_references( ACE_TEXT_ALWAYS_CHAR ("RootPOA")); + + if (CORBA::is_nil (poa_object.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT (" (%P|%t) Unable to initialize ") + ACE_TEXT ("the POA.\n")), + -1); + + this->root_poa_ = PortableServer::POA::_narrow (poa_object.in ()); + + PortableServer::POAManager_var poa_manager = + this->root_poa_->the_POAManager (); + + poa_manager->activate (); + + ACE_Time_Value timeout (10); // Wait up to 10 seconds for the naming service + if (name_svc_.init (this->orb_, &timeout) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + ACE_TEXT (" (%P|%t) LB_server: Could not connect ") + ACE_TEXT ("to naming service.\n")), + -1); + + CORBA::Object_var obj = this->orb_->resolve_initial_references ( + ACE_TEXT_ALWAYS_CHAR ("NamingManager")); + + this->naming_manager_ = + FT_Naming::NamingManager::_narrow (obj.in ()); + + if (CORBA::is_nil (this->naming_manager_.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT (" (%P|%t) Unable to get Naming Manager ") + ACE_TEXT ("Reference.\n")), + -1); + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Exception raised initialising ORB or POA")); + return -1; + } + + return 0; + +} + +int +LB_server::create_object_group (void) +{ + try + { + if (this->parse_args (argc_, argv_) != 0) + return -1; + + PortableGroup::Criteria criteria (2); + criteria.length (1); + + PortableGroup::Property &mem_style = criteria[0]; + mem_style.nam.length (1); + + // Set the membership style property + mem_style.nam[0].id = CORBA::string_dup ( + ACE_TEXT_ALWAYS_CHAR ("org.omg.PortableGroup.MembershipStyle")); + + PortableGroup::MembershipStyleValue msv = + PortableGroup::MEMB_APP_CTRL; + mem_style.val <<= msv; + + this->object_group_ = this->naming_manager_->create_object_group ( + ACE_TEXT_ALWAYS_CHAR ("BasicGroup"), + FT_Naming::ROUND_ROBIN, + criteria); + + CORBA::String_var ior = + this->orb_->object_to_string (this->object_group_.in ()); + + this->write_ior_to_file (ior.in ()); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Exception raised while creating object group")); + return -1; + } + + return 0; + +} + +int +LB_server::register_servant (Basic *servant, const char *loc) +{ + try + { + Test::Basic_var basic = + servant->_this (); + + PortableGroup::Location location (1); + location.length (1); + + location[0].id = CORBA::string_dup (loc); + + this->naming_manager_->add_member (this->object_group_.in (), + location, + basic.in ()); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Exception raised while registering servant")); + return -1; + } + + return 0; +} + +TAO_Naming_Client& +LB_server::name_svc () +{ + return name_svc_; +} diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/LB_server.h b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/LB_server.h new file mode 100644 index 00000000000..d6df78c52f8 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/LB_server.h @@ -0,0 +1,98 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file LB_server.h + * + * $Id$ + * + * @author Jaiganesh Balasubramanian <jai@doc.ece.uci.edu> + * @author Ossama Othman <ossama@uci.edu> + */ +//============================================================================= + + +#include "orbsvcs/FT_NamingManagerC.h" +#include "orbsvcs/PortableGroupC.h" +#include "tao/PortableServer/PortableServer.h" +#include "ace/Get_Opt.h" +#include "orbsvcs/Naming/Naming_Client.h" + +// Forward Declaration of the kind of servant we would like to handle +// by the server. +class Basic; + +/** + * @class LB_server + * + * @brief Encapsulate the test in class. + * + * TODO: Fix description + * This is a class used to retrieve the NamingManager reference and + * create the Object Group. Servants add themselves to the object + * group and the object group reference is published to the clients. + * Clients then invoke the "servant operations" on the NamingManager + * itself. At this point the Load Balancing cycle starts. + */ +class LB_server +{ +public: + + /// Constructor + LB_server (int argc, ACE_TCHAR **argv); + + /// destroys NamingManager, ORB and POA. + int destroy (void); + + /// start the ORB. + int start_orb_and_poa (void); + + /// Get the NamingManager Interface. + int init (int argc, ACE_TCHAR **argv); + + /// Create the Object Group using the Load Manager Reference. + int create_object_group (void); + + /// register the servants with the object group. + int register_servant (Basic *servant, const char *loc); + + /// obtain the name service facade + TAO_Naming_Client& name_svc (); + + /// for servants to register to the initialised ORB. + CORBA::ORB_ptr orb (void); + + /// for servants to get the reference for object_group. + CORBA::Object_ptr object_group (void); + + /// for servants to get the reference for object_group. + FT_Naming::NamingManager_ptr naming_manager (void); + +private: + + int parse_args (int, ACE_TCHAR **); + +private: + + /// Load Manager + FT_Naming::NamingManager_var naming_manager_; + + /// Object Group. + CORBA::Object_var object_group_; + + /// factory id for the object group. + PortableGroup::GenericFactory::FactoryCreationId_var fcid_; + + /// Used to force the creation of the object group only once. + static int called_once_; + + /// write the IOR to a file so that it can be read later. + int write_ior_to_file (const char *); + + CORBA::ORB_var orb_; + int argc_; + ACE_TCHAR **argv_; + PortableServer::POA_var root_poa_; + const ACE_TCHAR *ior_output_file_; + TAO_Naming_Client name_svc_; +}; diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/README b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/README new file mode 100644 index 00000000000..ba1c835824b --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/README @@ -0,0 +1,234 @@ +$Id$ + +This program tests the following fault tolerant naming service implementation +use cases: + +1) Failover: Validate that a client can seamlessly connect to the alternate + server of a server naming server pair after the other server has been + terminated. + +2) Persistence: Validate that repository data written by the naming service is + available upon startup. + +3) Equivalence: Validate that a client can seamlessly invoke naming operations + on either server instance. + + +================================================================================ +Failover Test +================================================================================ + +<hostname> = <local_host> +<port1> = <first unused port> +<port2> = <second unused port> + +1) Create empty NameService and GroupService directories + + cd $TAO_ROOT/orbsvcs/tests/FT_Naming/FaultTolerant + mkdir NameService + mkdir GroupService + +2) Start primary tao_ft_naming process + $TAO_ROOT/orbsvcs/Naming_Service/tao_ft_naming --primary \ + -ORBListenEndPoints iiop://<hostname>:<port1> \ + -m 0 \ + -r NameService \ + -v GroupService & + +3) Start backup tao_ft_naming process + + $TAO_ROOT/orbsvcs/Naming_Service/tao_ft_naming --backup \ + -ORBListenEndPoints iiop://<hostname>:<port2> \ + -m 0 \ + -c $TAO_ROOT/orbsvcs/tests/FT_Naming/FaultTolerant/ns.ior \ + -g $TAO_ROOT/orbsvcs/tests/FT_Naming/FaultTolerant/nm.ior \ + -r NameService \ + -v GroupService & + +4) Terminate primary tao_ft_naming process + +5) Run client with failover argument + + client --failover \ + -p file:///$TAO_ROOT/orbsvcs/tests/FT_Naming/FaultTolerant/ns.ior \ + -r file://$TAO_ROOT/orbsvcs/tests/FT_Naming/FaultTolerant/nm.ior \ + -b 4 -d 4 + + ============================================================================== + Example Output: + ============================================================================== + INFO: Failover Name Test OK + INFO: nm1ref: file:///tmp/ramdisk/tmp/nm.ior + INFO: Object Group Found In Repository + INFO: Failover ObjectGroup Test OK + +6) Cleanup + + rm -rf NameService + rm -rf GroupService + +================================================================================ +Persistence Test +================================================================================ + +<hostname> = <local_host> +<port1> = <unused port> + +1) Create empty NameService and GroupService directories + + cd $TAO_ROOT/orbsvcs/tests/FT_Naming/FaultTolerant + mkdir NameService + mkdir GroupService + +2) Start tao_ft_naming + + $TAO_ROOT/orbsvcs/Naming_Service/tao_ft_naming \ + -ORBListenEndPoints iiop://<hostname>:<port1> \ + -g $TAO_ROOT/orbsvcs/tests/FT_Naming/FaultTolerant/nm.ior \ + -o $TAO_ROOT/orbsvcs/tests/FT_Naming/FaultTolerant/ns.ior \ + -v GroupService \ + -u NameService & + +3) Start test object server + + server -ORBDefaultInitRef corbaloc:iiop:<hostname>:<port1> \ + -o $TAO_ROOT/orbsvcs/tests/FT_Naming/FaultTolerant/srv.ior & + +4) Run the test client with the persistence and create arguments + + client --persistence --create \ + -p corbaloc:iiop:<hostname>:<port1>/NameService \ + -r corbaloc:iiop:<hostname>:<port1>/NamingManager \ + -b 4 -d 4 + + ============================================================================== + Example Output: + ============================================================================== + INFO: Persistence Creation Name Test OK + INFO: Object Group BasicGroup Found In Repository + INFO: validating group member location1 + INFO: object group member at location1 reports location1 + INFO: validating group member location2 + INFO: object group member at location2 reports location2 + INFO: validating group member location3 + INFO: object group member at location3 reports location3 + INFO: validating group member location4 + INFO: object group member at location4 reports location4 + INFO: validating group member location5 + INFO: object group member at location5 reports location5 + INFO: validating group member location6 + INFO: object group member at location6 reports location6 + INFO: Persistence Creation ObjectGroup Test OK + + +5) Terminate tao_ft_naming and then restart it with the original arguments + + kill `pidof $TAO_ROOT/orbsvcs/Naming_Service/tao_ft_naming` + + $TAO_ROOT/orbsvcs/Naming_Service/tao_ft_naming \ + -ORBListenEndPoints iiop://<hostname>:<port1> \ + -g $TAO_ROOT/orbsvcs/tests/FT_Naming/FaultTolerant/nm.ior \ + -o $TAO_ROOT/orbsvcs/tests/FT_Naming/FaultTolerant/ns.ior \ + -v GroupService \ + -u NameService & + +6) Now run the test client with the persistence and valdiate arguments + + client --persistence --validate \ + -p corbaloc:iiop:<hostname>:<port1>/NameService \ + -r corbaloc:iiop:<hostname>:<port1>/NamingManager \ + -b 4 -d 4 + + ============================================================================== + Example Output: + ============================================================================== + INFO: Persistence Validation Name Test OK + INFO: Object Group BasicGroup Found In Repository + INFO: validating group member location1 + INFO: object group member at location1 reports location1 + INFO: validating group member location2 + INFO: object group member at location2 reports location2 + INFO: validating group member location3 + INFO: object group member at location3 reports location3 + INFO: validating group member location4 + INFO: object group member at location4 reports location4 + INFO: validating group member location5 + INFO: object group member at location5 reports location5 + INFO: validating group member location6 + INFO: object group member at location6 reports location6 + INFO: Persistence Validation ObjectGroup Test OK + +7) Cleanup + + rm -rf NameService + rm -rf GroupService + + +================================================================================ +Redundant Equivalancy Test +================================================================================ + +<hostname> = <local_host> +<port1> = <first unused port> +<port2> = <second unused port> + +1) Create empty NameService and GroupService directories + + cd $TAO_ROOT/orbsvcs/tests/FT_Naming/FaultTolerant + mkdir NameService + mkdir GroupService + +2) Start primary tao_ft_naming process + + $TAO_ROOT/orbsvcs/Naming_Service/tao_ft_naming \ + --primary \ + -ORBListenEndPoints iiop://<hostname>:<port1> \ + -o /tmp/ns_primary.ior \ + -h /tmp/nm_primary.ior \ + -r NameService \ + -v GroupService & + +3) Start backup tao_ft_naming process + + $TAO_ROOT/orbsvcs/Naming_Service/tao_ft_naming \ + --backup \ + -ORBListenEndPoints iiop://<hostname>:<port2> \ + -o /tmp/ns_backup.ior \ + -h /tmp/nm_backup.ior \ + -c /tmp/ns_multi_profile.ior \ + -g /tmp/nm_multi_profile.ior \ + -r NameService \ + -v GroupService & + +4) Now run the test client with the equivalence argument + + client --equivalence \ + -p file:///tmp/ns_primary.ior \ + -q file:///tmp/ns_backup.ior \ + -r file:///tmp/nm_primary.ior \ + -s file:///tmp/nm_backup.ior \ + -b 4 -d 4 + + ============================================================================== + Example Output: + ============================================================================== + INFO: ns1ref is not equivalent to ns2ref + INFO: ns1ref profile count: 1 + INFO: ns2ref profile count: 1 + INFO: Equivalence Name Test OK + INFO: nm1ref: file:///tmp/nm_primary.ior + INFO: nm2ref: file:///tmp/nm_backup.ior + INFO: nm1ref is not equivalent to nm2ref + INFO: nm1ref profile count: 1 + INFO: nm2ref profile count: 1 + INFO: Primary Found Object Group test_group_1 Created By Primary In Repository + INFO: Backup Found Object Group test_group_2 Created By Backup In Repository + INFO: Primary Found Object Group test_group_2 Created By Backup In Repository + INFO: Backup Found Object Group test_group_1 Created By Primary In Repository + INFO: Equivalence ObjectGroup Test OK + +5) Cleanup + + rm -rf NameService + rm -rf GroupService + diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/Test.idl b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/Test.idl new file mode 100644 index 00000000000..21d10f6644c --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/Test.idl @@ -0,0 +1,27 @@ +// +// $Id$ + +#include "orbsvcs/FT_NamingManager.idl" + +/// Put the interfaces in a module, to avoid global namespace pollution +module Test +{ + typedef FT_Naming::LoadBalancingStrategyValue LoadBalancingStrategyValue; + + /// A very simple interface + interface Basic + { + /// Return a simple string + string get_string (); + + /// A method to shutdown the ORB + /** + * This method is used to simplify the test shutdown process + */ + oneway void shutdown (); + + /// A method to remove the servant from the NamingManager Object Group. + oneway void remove_member (); + }; +}; + diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/client.cpp b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/client.cpp new file mode 100644 index 00000000000..1b4b8a6d975 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/client.cpp @@ -0,0 +1,2324 @@ +//============================================================================= +/** + * @file client.cpp + * + * $Id$ + * + * This class implements a CORBA test client for the Fault Tolerant Naming Service. + * + * @author Rich Seibel <seibel_r@ociweb.com> + * @author Phillip LaBanca <labancap@ociweb.com> + */ +//============================================================================= + +#include "TestC.h" +#include "test_objectS.h" +#include "orbsvcs/CosNamingC.h" +#include "orbsvcs/FT_NamingManagerC.h" +#include "orbsvcs/Naming/Naming_Server.h" +#include "tao/debug.h" +#include "tao/Stub.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "orbsvcs/Naming/FaultTolerant/nsgroup_svc.h" + +#if defined (_MSC_VER) +# pragma warning (disable : 4250) +#endif /* _MSC_VER */ + +//============================================================================== +// +//============================================================================== +class My_Test_Object : + public virtual POA_Test_Object +{ +public: + // = Initialization and termination methods. + My_Test_Object (CORBA::Short id = 0); + // Constructor. + + ~My_Test_Object (void); + // Destructor. + + // = Interface implementation accessor methods. + + void id (CORBA::Short id); + // Sets id. + + CORBA::Short id (void); + // Gets id. + +private: + short id_; +}; + +My_Test_Object::My_Test_Object (CORBA::Short id) + : id_ (id) +{ +} + +My_Test_Object::~My_Test_Object (void) +{ +} + +CORBA::Short +My_Test_Object::id (void) +{ + return id_; +} + +void +My_Test_Object::id (CORBA::Short id) +{ + id_ = id; +} + +//============================================================================== +// +//============================================================================== +/// Failover Name Test +int +do_failover_name_test ( + CORBA::ORB_ptr theOrb, + ACE_TCHAR *ns1ref, + int c_breadth, + int c_depth, + int o_breadth ); + +/// Failover ObjectGroup Test +int +do_failover_objectgroup_test ( + CORBA::ORB_ptr theOrb, + ACE_TCHAR *nm1ref, + int c_breadth, + int c_depth, + int o_breadth ); + +//============================================================================== +// +//============================================================================== +/// Persistence Name Test +int +do_persistence_name_test ( + CORBA::ORB_ptr theOrb, + ACE_TCHAR *ns1ref, + int c_breadth, + int c_depth, + int o_breadth, + bool validate_only); + +/// Persistence ObjectGroup Test +int +do_persistence_objectgroup_test ( + CORBA::ORB_ptr theOrb, + ACE_TCHAR *nm1ref, + int c_breadth, + int c_depth, + int o_breadth, + bool validate_only); + +//============================================================================== +// +//============================================================================== +/// Equivalence Name Test +int +do_equivalence_name_test ( + CORBA::ORB_ptr theOrb, + ACE_TCHAR *ns1ref, + ACE_TCHAR *ns2ref, + int c_breadth, + int c_depth, + int o_breadth); + +/// Equivalence ObjectGroup Test +int +do_equivalence_objectgroup_test ( + CORBA::ORB_ptr theOrb, + ACE_TCHAR *nm1ref, + ACE_TCHAR *nm2ref, + int c_breadth, + int c_depth, + int o_breadth); + + +//============================================================================== +// +//============================================================================== +int +ACE_TMAIN(int argc, ACE_TCHAR *argv[]) +{ + const int RC_SUCCESS = 0; + const int RC_ERROR = 1; + + int rc = RC_SUCCESS; + + int c_breadth = 4; + int c_depth = 4; + int o_breadth = 4; + + ACE_TCHAR *ns1ref = 0; + ACE_TCHAR *ns2ref = 0; + + ACE_TCHAR *nm1ref = 0; + ACE_TCHAR *nm2ref = 0; + + typedef enum { + TT_FAILOVER, + TT_PERSISTENCE, + TT_EQUIVALENCE + } fault_tolerant_test; + fault_tolerant_test test_type = TT_FAILOVER; + + typedef enum { + TT_INIT, + TT_CREATE, + TT_VALIDATE + } fault_tolerant_test_phase; + fault_tolerant_test_phase test_phase = TT_INIT; + + ////////////////////////////////////////////////////////////////////////////// + // optional + ////////////////////////////////////////////////////////////////////////////// + // -b <breadth of context tree> + // -d <depth of context tree> + // -o <breadth of object tree> + ////////////////////////////////////////////////////////////////////////////// + // required + ////////////////////////////////////////////////////////////////////////////// + // -p <ior of first name server> + // -q <ior of second name server> + // -r <ior of first naming service> + // -s <ior of second naming service> + // --failover run fault tolerant failover test + // --persistence run fault tolerant persistence test + // --equivalence run fault tolerant equivalence test + ////////////////////////////////////////////////////////////////////////////// + // required with persistance + ////////////////////////////////////////////////////////////////////////////// + // --create run creation test phase + // --validate run validation test phase + + try + { + // Initialize orb + CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); + + ACE_Get_Opt get_opts (argc, argv, ACE_TEXT ("b:d:o:p:q:r:s:")); + int c; + int i; + get_opts.long_option (ACE_TEXT ("failover"), ACE_Get_Opt::NO_ARG); + get_opts.long_option (ACE_TEXT ("persistence"), ACE_Get_Opt::NO_ARG); + get_opts.long_option (ACE_TEXT ("equivalence"), ACE_Get_Opt::NO_ARG); + get_opts.long_option (ACE_TEXT ("create"), ACE_Get_Opt::NO_ARG); + get_opts.long_option (ACE_TEXT ("validate"), ACE_Get_Opt::NO_ARG); + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'b': + i = ACE_OS::atoi(get_opts.opt_arg ()); + if (i<2) + { + ACE_ERROR((LM_ERROR, + ACE_TEXT ("Invalid breadth, must be 2 or more\n"))); + ACE_OS::exit(RC_ERROR); + } + c_breadth = i; + break; + case 'd': + i = ACE_OS::atoi(get_opts.opt_arg ()); + if (i<2) + { + ACE_ERROR((LM_ERROR, + ACE_TEXT ("Invalid depth, must be 2 or more\n"))); + ACE_OS::exit(RC_ERROR); + } + c_depth = i; + break; + case 'o': + i = ACE_OS::atoi(get_opts.opt_arg ()); + if (i<2) + { + ACE_ERROR((LM_ERROR, + ACE_TEXT ("Invalid breadth, must be 2 or more\n"))); + ACE_OS::exit(RC_ERROR); + } + o_breadth = i; + break; + case 'p': + ns1ref = get_opts.opt_arg (); + break; + case 'q': + ns2ref = get_opts.opt_arg (); + break; + case 'r': + nm1ref = get_opts.opt_arg (); + break; + case 's': + nm2ref = get_opts.opt_arg (); + break; + case 0: // A long option was found + { + const char* long_option = get_opts.long_option (); + if (ACE_OS::strcmp (long_option, + ACE_TEXT ("failover")) == 0) + { + test_type = TT_FAILOVER; + } + else if (ACE_OS::strcmp (long_option, + ACE_TEXT ("persistence")) == 0) + { + test_type = TT_PERSISTENCE; + } + else if (ACE_OS::strcmp (long_option, + ACE_TEXT ("equivalence")) == 0) + { + test_type = TT_EQUIVALENCE; + } + else if (ACE_OS::strcmp (long_option, + ACE_TEXT ("create")) == 0) + { + test_phase = TT_CREATE; + } + else if (ACE_OS::strcmp (long_option, + ACE_TEXT ("validate")) == 0) + { + test_phase = TT_VALIDATE; + } + } + break; + + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Argument %c \n usage: %s") + ACE_TEXT (" [-b <breadth of context tree>]") + ACE_TEXT (" [-d <depth of context tree>]") + ACE_TEXT (" [-o <breadth of object tree>]") + ACE_TEXT (" -p <ior of first name server>") + ACE_TEXT (" -q <ior of second name server>") + ACE_TEXT (" -r <ior of first naming server>") + ACE_TEXT (" -s <ior of second naming server>") + ACE_TEXT ("\n")), + RC_ERROR); + } + + switch(test_type) { + + case TT_FAILOVER: + + if( RC_SUCCESS != do_failover_name_test ( + orb.in (), + ns1ref, + c_breadth, + c_depth, + o_breadth )) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ERROR: Failover Name Test Failed\n"))); + rc = RC_ERROR; + } else { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: Failover Name Test OK\n"))); + } + + if( RC_SUCCESS != do_failover_objectgroup_test ( + orb.in (), + nm1ref, + c_breadth, + c_depth, + o_breadth )) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ERROR: Failover ObjectGroup ") + ACE_TEXT ("Test Failed\n"))); + rc = RC_ERROR; + } else { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: Failover ObjectGroup Test OK\n"))); + } + + break; + + case TT_PERSISTENCE: + + switch(test_phase){ + + case TT_CREATE: + if (RC_SUCCESS != do_persistence_name_test ( + orb.in (), + ns1ref, + c_breadth, + c_depth, + o_breadth, + false )) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ERROR: Persistence Creation Name ") + ACE_TEXT ("Test Failed\n"))); + rc = RC_ERROR; + } else { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: Persistence Creation Name ") + ACE_TEXT ("Test OK\n"))); + } + if (RC_SUCCESS != do_persistence_objectgroup_test( + orb.in (), + nm1ref, + c_breadth, + c_depth, + o_breadth, + false )) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ERROR: Persistence Creation ObjectGroup ") + ACE_TEXT ("Test Failed\n"))); + rc = RC_ERROR; + } else { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: Persistence Creation ObjectGroup ") + ACE_TEXT ("Test OK\n"))); + } + break; + + case TT_VALIDATE: + if (RC_SUCCESS != do_persistence_name_test ( + orb.in (), + ns1ref, + c_breadth, + c_depth, + o_breadth, + true )) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ERROR: Persistence Validation ") + ACE_TEXT ("Name Test Failed\n"))); + rc = RC_ERROR; + } else { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: Persistence Validation ") + ACE_TEXT ("Name Test OK\n"))); + } + + if (RC_SUCCESS != do_persistence_objectgroup_test ( + orb.in (), + nm1ref, + c_breadth, + c_depth, + o_breadth, + true )) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ERROR: Persistence Validation ") + ACE_TEXT ("ObjectGroup Test Failed\n"))); + rc = RC_ERROR; + } else { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: Persistence Validation ") + ACE_TEXT ("ObjectGroup Test OK\n"))); + } + break; + + case TT_INIT: + default: + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ERROR: Missing Required Persistence ") + ACE_TEXT ("Argument [--create|--validate] \n"))); + rc = RC_ERROR; + break; + } + break; + + case TT_EQUIVALENCE: + + if (RC_SUCCESS != do_equivalence_name_test ( + orb.in (), + ns1ref, + ns2ref, + c_breadth, + c_depth, + o_breadth )) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ERROR: Equivalence Name Test\n"))); + rc = RC_ERROR; + } else { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: Equivalence Name Test OK\n"))); + } + + if (RC_SUCCESS != do_equivalence_objectgroup_test( + orb.in (), + nm1ref, + nm2ref, + c_breadth, + c_depth, + o_breadth )) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("ERROR: Equivalence ObjectGroup Test\n"))); + rc = RC_ERROR; + } else { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: Equivalence ObjectGroup Test OK\n"))); + } + break; + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to resolve name servers")); + return RC_ERROR; + } + + + return rc; + +} + +//============================================================================== +// +//============================================================================== +/// Failover Name Test +int +do_failover_name_test ( + CORBA::ORB_ptr theOrb, + ACE_TCHAR *ns1ref, + int c_breadth, + int c_depth, + int o_breadth ) +{ + const int RC_SUCCESS = 0; + const int RC_ERROR = -1; + CosNaming::NamingContext_var root_context_1; + int i; + + try { + + CORBA::ORB_var orb = CORBA::ORB::_duplicate(theOrb); + + if (CORBA::is_nil (orb.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid orb\n")), + RC_ERROR); + } + + if (CORBA::is_nil (ns1ref)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ns1\n")), + RC_ERROR); + } + + CORBA::Object_var ns1obj = + orb->string_to_object (ACE_TEXT_ALWAYS_CHAR (ns1ref)); + + if (CORBA::is_nil (ns1obj.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),ns1ref), + RC_ERROR); + } + + root_context_1 = CosNaming::NamingContext::_narrow (ns1obj.in ()); + + if (CORBA::is_nil (root_context_1.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),ns1ref), + RC_ERROR); + } + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to resolve name servers")); + return RC_ERROR; + } + + // Create a bunch of objects in one context + // Note: strings to the naming service must be char, not wchar + try + { + // Bind one context level under root. + CosNaming::Name level1; + level1.length (1); + level1[0].id = CORBA::string_dup ("level1_context"); + CosNaming::NamingContext_var level1_context; + level1_context = root_context_1->bind_new_context (level1); + ACE_OS::thr_yield (); + + for (i=0; i<o_breadth; i++) + { + // Instantiate a dummy object and bind it under the new context. + My_Test_Object *impl1 = new My_Test_Object (i+1); + Test_Object_var obj1 = impl1->_this (); + + impl1->_remove_ref (); + + level1.length (2); + + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("obj_%d"), i); + level1[1].id = CORBA::string_dup (wide_name); + + root_context_1->bind (level1, obj1.in ()); + ACE_OS::thr_yield (); + + // See if the newly bound object is available in the + // replica + try { + CORBA::Object_var obj1_on_replica = root_context_1->resolve (level1); + } + catch (const CosNaming::NamingContext::NotFound& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("INFO: Unable to resolve object from replica.\n")); + + // Try again... + try { + + CORBA::Object_var obj1_on_replica = + root_context_1->resolve (level1); + + // We did find the object on the replica, but only after a wait. + // This would be caused by a race condition to access the variable. + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("INFO: Object appeared after a short ") + ACE_TEXT ("wait.\n"))); + } + catch (const CosNaming::NamingContext::NotFound& second_ex) + { + second_ex._tao_print_exception ( + ACE_TEXT ("ERROR: It really is not there. Failing...\n")); + return RC_ERROR; + } + } + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to create a lot of objects")); + return RC_ERROR; + } + + // Create a deep context tree + try + { + CosNaming::NamingContext_var next_context = root_context_1; + for (i=0; i<c_depth; i++) + { + // Bind level1 context under root. + CosNaming::Name deep; + deep.length (1); + char deep_name[16]; + ACE_OS::sprintf(deep_name, ACE_TEXT_ALWAYS_CHAR ("deep_%d"), i); + deep[0].id = CORBA::string_dup (deep_name); + CosNaming::NamingContext_var deep_context; + deep_context = next_context->bind_new_context (deep); + ACE_OS::thr_yield (); + next_context = deep_context; + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to create deep context")); + return RC_ERROR; + } + + // Create a wide context tree + try + { + for (i=0; i<c_breadth; i++) + { + // Bind all level of context under root. + CosNaming::Name wide; + wide.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("wide_%d"), i); + wide[0].id = CORBA::string_dup (wide_name); + CosNaming::NamingContext_var wide_context; + wide_context = root_context_1->bind_new_context (wide); + ACE_OS::thr_yield (); + + try { + // Check if the new context is available in the replica + CORBA::Object_var obj1_on_replica = root_context_1->resolve (wide); + // Make sure it is a context + CosNaming::NamingContext_var nc = + CosNaming::NamingContext::_narrow (obj1_on_replica); + } + catch (const CosNaming::NamingContext::NotFound& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("INFO: Unable to resolve wide context object from ") + ACE_TEXT ("replica.\n")); + + // Try again to see if it just was a race condition + try { + CORBA::Object_var obj1_on_replica = root_context_1->resolve (wide); + // We did find the object on the replica, but only after a wait. + // This would be caused by a race condition to access the variable. + ACE_ERROR (( LM_ERROR, + ACE_TEXT ("INFO: Object appeared after a short ") + ACE_TEXT ("wait.\n"))); + } + catch (const CosNaming::NamingContext::NotFound& second_ex) + { + second_ex._tao_print_exception ( + ACE_TEXT ("ERROR: It really is not there. Failing...\n")); + return RC_ERROR; + } + } + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to create wide context")); + return RC_ERROR; + } + + // Delete three selected things, one from each tree + try { + // Remove the second to last object from the Naming Context + CosNaming::Name wide1; + wide1.length (2); + wide1[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("level1_context")); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("obj_%d"), o_breadth-2); + wide1[1].id = CORBA::string_dup (wide_name); + root_context_1->unbind (wide1); + ACE_OS::thr_yield (); + + bool retried = false; + // Make sure it is gone from the replica + try { + CORBA::Object_var obj1_on_replica = root_context_1->resolve (wide1); + + // An exception should be thrown by the above or + // there is an error. This means the replica did + // not register the loss of the context. + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("INFO: Unbound deep context not removed from ") + ACE_TEXT ("replica. Trying again...\n"))); + retried = true; // Mark this so it can be reported in catch block. + + obj1_on_replica = root_context_1->resolve (wide1); + + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: Unbound context not removed from ") + ACE_TEXT ("on retry\n")), + RC_ERROR); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Not on replica --- as it should be. + if (retried) // Was found on the retry + ACE_ERROR (( LM_ERROR, + ACE_TEXT ("INFO: Was removed after short wait.\n"))); + } + + // Remove the second to last context from the wide root Naming Context + CosNaming::Name wide2; + wide2.length (1); + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("wide_%d"), c_breadth-2); + wide2[0].id = CORBA::string_dup (wide_name); + + CORBA::Object_var result_obj_ref = root_context_1->resolve (wide2); + + CosNaming::NamingContext_var result_object = + CosNaming::NamingContext::_narrow (result_obj_ref.in ()); + + if (CORBA::is_nil (result_object.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving wide context ") + ACE_TEXT ("- nil object ref.\n")), + RC_ERROR); + } + + result_object->destroy(); + root_context_1->unbind (wide2); + ACE_OS::thr_yield (); + + // Remove the last context from the deep Naming Context + CosNaming::Name deep; + deep.length (c_depth); + + char deep_name[16]; + for (i=0; i<c_depth; i++) + { + ACE_OS::sprintf(deep_name, ACE_TEXT_ALWAYS_CHAR ("deep_%d"), i); + deep[i].id = CORBA::string_dup (deep_name); + } + + result_obj_ref = root_context_1->resolve (deep); + + result_object = CosNaming::NamingContext::_narrow (result_obj_ref.in ()); + if (CORBA::is_nil (result_object.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving deep context ") + ACE_TEXT ("- nil object ref.\n")), + RC_ERROR); + } + + result_object->destroy(); + root_context_1->unbind (deep); + ACE_OS::thr_yield (); + + retried = false; + // Make sure it is gone from the replica + try { + CORBA::Object_var obj1_on_replica = root_context_1->resolve (deep); + + // An exception should be thrown by the above or + // there is an error. This means the replica did + // not register the loss of the context. + ACE_ERROR (( LM_ERROR, + ACE_TEXT ("INFO: Unbound deep context not removed from ") + ACE_TEXT ("replica. Trying again...\n"))); + + retried = true; // Mark this so it can be reported in catch block. + obj1_on_replica = root_context_1->resolve (deep); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Unbound context not removed from ") + ACE_TEXT ("on retry\n")), + RC_ERROR); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Not on replica --- as it should be. + if (retried) // Was found on the retry + ACE_ERROR (( LM_ERROR, + ACE_TEXT ("INFO: Was removed after short wait.\n"))); + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to delete objects")); + return RC_ERROR; + } + + // Now use the other name server to access 3 objects next to the + // deleted objects and the 3 deleted objects + try + { + // Access the last object from the Naming Context + CosNaming::Name wide; + wide.length (2); + wide[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("level1_context")); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("obj_%d"), o_breadth-1); + wide[1].id = CORBA::string_dup (wide_name); + CORBA::Object_var result_obj_ref = root_context_1->resolve (wide); + Test_Object_var result_object = Test_Object::_narrow (result_obj_ref.in ()); + if (CORBA::is_nil (result_object.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving object from ") + ACE_TEXT ("redundant server - nil object ref.\n")), + RC_ERROR); + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to resolve object from redundant server")); + return RC_ERROR; + } + + try + { + // Access the deleted second to last object from the Naming Context + CosNaming::Name wide; + wide.length (2); + wide[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("level1_context")); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("obj_%d"), o_breadth-2); + wide[1].id = CORBA::string_dup (wide_name); + + CORBA::Object_var result_obj_ref = root_context_1->resolve (wide); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving object from ") + ACE_TEXT ("redundant server - deleted object found.\n")), + RC_ERROR); + } + catch (const CosNaming::NamingContext::NotFound& ex) + { + // expect exception since the context was deleted. + // Make sure the right exception reason is provided. + if (ex.why != CosNaming::NamingContext::missing_node) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Wrong exception returned during resolve.\n")), + RC_ERROR); + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Wrong exception type returned from resolve.\n")); + return RC_ERROR; + } + + try + { + // Access the last context from the wide Naming Context + CosNaming::Name wide; + wide.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("wide_%d"), c_breadth-1); + wide[0].id = CORBA::string_dup (wide_name); + + CORBA::Object_var result_obj_ref = root_context_1->resolve (wide); + + CosNaming::NamingContext_var result_object = + CosNaming::NamingContext::_narrow (result_obj_ref.in ()); + + if (CORBA::is_nil (result_object.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving wide context from ") + ACE_TEXT ("redundant server - nil object ref.\n")), + RC_ERROR); + } + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Expected exception + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( ACE_TEXT ("ERROR: Unexpected Exception received.\n")); + return RC_ERROR; + } + + try + { + // Access the deleted second to last object from the Naming Context + CosNaming::Name wide; + wide.length (2); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("wide_%d"), c_breadth-2); + wide[0].id = CORBA::string_dup (wide_name); + + CORBA::Object_var result_obj_ref = root_context_1->resolve (wide); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving wide context from ") + ACE_TEXT ("redundant server - deleted object found.\n")), + RC_ERROR); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Expected exception + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( ACE_TEXT ("ERROR: Unexpected Exception received.\n")); + return RC_ERROR; + } + + try + { + // Access the deleted last context from the deep Naming Context + CosNaming::Name deep; + deep.length (c_depth); + char deep_name[16]; + for (i=0; i<c_depth; i++) + { + ACE_OS::sprintf(deep_name, ACE_TEXT_ALWAYS_CHAR ("deep_%d"), i); + deep[i].id = CORBA::string_dup (deep_name); + } + + CORBA::Object_var result_obj_ref = root_context_1->resolve (deep); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving deep context from ") + ACE_TEXT ("redundant server - deleted object found.\n")), + RC_ERROR); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Expected exception + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unexpected Exception received resolving ") + ACE_TEXT ("deep cxt from redundant server.\n")); + return RC_ERROR; + } + + try + { + // Access the second to last object from the Naming Context + CosNaming::Name deep; + deep.length (c_depth-1); + char deep_name[16]; + for (i=0; i<c_depth-1; i++) + { + ACE_OS::sprintf(deep_name, ACE_TEXT_ALWAYS_CHAR ("deep_%d"), i); + deep[i].id = CORBA::string_dup (deep_name); + } + + CORBA::Object_var result_obj_ref = + root_context_1->resolve (deep); + + CosNaming::NamingContext_var result_object = + CosNaming::NamingContext::_narrow (result_obj_ref.in ()); + + if (CORBA::is_nil (result_object.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving deep context from ") + ACE_TEXT ("redundant server - nil object ref.\n")), + RC_ERROR); + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to resolve deep context from redundant server")); + return RC_ERROR; + } + + return RC_SUCCESS; +} + +/// Failover ObjectGroup Test +int +do_failover_objectgroup_test ( + CORBA::ORB_ptr theOrb, + ACE_TCHAR *nm1ref, + int c_breadth, + int c_depth, + int o_breadth ) +{ + ACE_UNUSED_ARG (c_breadth); + ACE_UNUSED_ARG (c_depth); + ACE_UNUSED_ARG (o_breadth); + + const int RC_SUCCESS = 0; + const int RC_ERROR = -1; + + FT_Naming::NamingManager_var naming_manager_1; + + try { + + CORBA::ORB_var orb = CORBA::ORB::_duplicate(theOrb); + if (CORBA::is_nil (orb.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid orb\n")), + RC_ERROR); + } + + if (CORBA::is_nil (nm1ref)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid nm1\n")), + RC_ERROR); + } + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("INFO: nm1ref: %s\n"), nm1ref)); + + CORBA::Object_var nm1obj = + orb->string_to_object (ACE_TEXT_ALWAYS_CHAR (nm1ref)); + + if (CORBA::is_nil (nm1obj.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),nm1ref), + RC_ERROR); + } + + naming_manager_1 = FT_Naming::NamingManager::_narrow (nm1obj.in ()); + if (CORBA::is_nil (naming_manager_1.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),nm1ref), + RC_ERROR); + } + + NS_group_svc svc; + + if (RC_SUCCESS != svc.set_orb (theOrb)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid orb\n")), + RC_ERROR); + } + + if (RC_SUCCESS != svc.set_naming_manager (naming_manager_1)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),nm1ref), + RC_ERROR); + } + + + const char* test_group = "test_group"; + const char* policy = "round"; + + if (RC_SUCCESS != svc.group_create (test_group, policy)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: unable to create %s\n"),test_group), + RC_ERROR); + } + + if (false == svc.group_exist(test_group)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: Object Group Not Found In Repository\n")), + RC_ERROR); + } else { + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("INFO: Object Group Found In Repository\n"))); + } + + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to resolve name manager servers")); + return RC_ERROR; + } + + return RC_SUCCESS; +} + + +//============================================================================== +// +//============================================================================== +/// Persistence Name Test +int +do_persistence_name_test ( + CORBA::ORB_ptr theOrb, + ACE_TCHAR *ns1ref, + int c_breadth, + int c_depth, + int o_breadth, + bool validate_only) +{ + const int RC_ERROR = -1; + const int RC_SUCCESS = 0; + CosNaming::NamingContext_var root_context_1; + int i; + + try { + + CORBA::ORB_var orb = CORBA::ORB::_duplicate(theOrb); + + if (CORBA::is_nil (orb.in () )) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid orb\n")), + RC_ERROR); + } + + if (CORBA::is_nil (ns1ref)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ns1\n")), + RC_ERROR); + } + + CORBA::Object_var ns1obj = + orb->string_to_object (ACE_TEXT_ALWAYS_CHAR (ns1ref)); + + if (CORBA::is_nil (ns1obj.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),ns1ref), + RC_ERROR); + } + + root_context_1 = CosNaming::NamingContext::_narrow (ns1obj.in ()); + + if (CORBA::is_nil (root_context_1.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),ns1ref), + RC_ERROR); + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("ERROR: Unable to resolve name servers")); + return RC_ERROR; + } + + // Create a bunch of objects in one context + // Note: strings to the naming service must be char, not wchar + try + { + // Bind one context level under root. + CosNaming::Name level1; + level1.length (1); + level1[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("level1_context")); + + if( false == validate_only ) { + CosNaming::NamingContext_var level1_context; + level1_context = root_context_1->bind_new_context (level1); + ACE_OS::thr_yield (); + } + + for (i=0; i<o_breadth; i++) + { + // Instantiate a dummy object and bind it under the new context. + My_Test_Object *impl1 = new My_Test_Object (i+1); + Test_Object_var obj1 = impl1->_this (); + impl1->_remove_ref (); + + level1.length (2); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("obj_%d"), i); + level1[1].id = CORBA::string_dup (wide_name); + + if( false == validate_only ) { + root_context_1->bind (level1, obj1.in ()); + ACE_OS::thr_yield (); + } + + + // See if the newly bound object is available in the repository + try { + CORBA::Object_var obj1_on_replica = root_context_1->resolve (level1); + } + catch (const CosNaming::NamingContext::NotFound& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to resolve object from repository.\n")); + + // Try again... + try { + CORBA::Object_var obj1_on_replica = root_context_1->resolve (level1); + // We did find the object on the repository, but only after a wait. + // This would be caused by a race condition to access the variable. + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("INFO: Object appeared after a short wait.\n"))); + } + catch (const CosNaming::NamingContext::NotFound& second_ex) + { + second_ex._tao_print_exception ( + ACE_TEXT ("ERROR: It really is not there. Failing...\n")); + return RC_ERROR; + } + } + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to create or validate a lot of objects")); + + return RC_ERROR; + } + + if( false == validate_only ) { + // Create a deep context tree + try + { + CosNaming::NamingContext_var next_context = root_context_1; + for (i=0; i<c_depth; i++) + { + // Bind level1 context under root. + CosNaming::Name deep; + deep.length (1); + char deep_name[16]; + ACE_OS::sprintf(deep_name, ACE_TEXT_ALWAYS_CHAR ("deep_%d"), i); + deep[0].id = CORBA::string_dup (deep_name); + + CosNaming::NamingContext_var deep_context; + deep_context = next_context->bind_new_context (deep); + ACE_OS::thr_yield (); + next_context = deep_context; + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("ERROR: Unable to create deep context")); + return RC_ERROR; + } + } + + // Create a wide context tree + try + { + for (i=0; i<c_breadth; i++) + { + // Bind all level of context under root. + CosNaming::Name wide; + wide.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("wide_%d"), i); + wide[0].id = CORBA::string_dup (wide_name); + + if( false == validate_only ) { + CosNaming::NamingContext_var wide_context; + wide_context = root_context_1->bind_new_context (wide); + ACE_OS::thr_yield (); + } + + try { + + // Check if the new context is available in the repository + CORBA::Object_var obj1_on_replica = + root_context_1->resolve (wide); + + // Make sure it is a context + CosNaming::NamingContext_var nc = + CosNaming::NamingContext::_narrow (obj1_on_replica); + } + catch (const CosNaming::NamingContext::NotFound& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("INFO: Unable to resolve wide context object from ") + ACE_TEXT ("repository.\n")); + + // Try again to see if it just was a race condition + try { + CORBA::Object_var obj1_on_replica = root_context_1->resolve (wide); + // We did find the object on the replica, but only after a wait. + // This would be caused by a race condition to access the variable. + ACE_ERROR (( LM_ERROR, + ACE_TEXT ("INFO: Object appeared after a short ") + ACE_TEXT ("wait.\n"))); + } + catch (const CosNaming::NamingContext::NotFound& second_ex) + { + second_ex._tao_print_exception ( + ACE_TEXT ("ERROR: It really is not there. Failing...\n")); + return RC_ERROR; + } + } + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to create or validate wide context")); + return RC_ERROR; + } + + return RC_SUCCESS; + +} + + +/// Persistence ObjectGroup Test +int +do_persistence_objectgroup_test ( + CORBA::ORB_ptr theOrb, + ACE_TCHAR *nm1ref, + int c_breadth, + int c_depth, + int o_breadth, + bool validate_only) +{ + ACE_UNUSED_ARG (c_breadth); + ACE_UNUSED_ARG (c_depth); + ACE_UNUSED_ARG (o_breadth); + ACE_UNUSED_ARG (validate_only); + + const int RC_ERROR = -1; + const int RC_SUCCESS = 0; + + FT_Naming::NamingManager_var naming_manager_1; + + try { + + CORBA::ORB_var orb = CORBA::ORB::_duplicate(theOrb); + + if (CORBA::is_nil (orb.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid orb\n")), + RC_ERROR); + } + + if (CORBA::is_nil (nm1ref)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid nm1\n")), + RC_ERROR); + } + + //ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("nm1ref: %s\n"), nm1ref)); + + CORBA::Object_var nm1obj = + orb->string_to_object (ACE_TEXT_ALWAYS_CHAR (nm1ref)); + + if (CORBA::is_nil (nm1obj.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),nm1ref), + RC_ERROR); + } + + naming_manager_1 = FT_Naming::NamingManager::_narrow (nm1obj.in ()); + if (CORBA::is_nil (naming_manager_1.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),nm1ref), + RC_ERROR); + } + + NS_group_svc group_svc; + + if( RC_SUCCESS != group_svc.set_orb (theOrb) ) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid orb\n")), + RC_ERROR); + } + + if( RC_SUCCESS != group_svc.set_naming_manager (naming_manager_1) ) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),nm1ref), + RC_ERROR); + } + + /// get BasicGroup member object and verify that it reports the same location + const char* basic_group_name = "BasicGroup"; + + if (false == group_svc.group_exist(basic_group_name)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: Object Group %s Not Found In Repository\n"), + basic_group_name), + RC_ERROR); + } else { + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("INFO: Object Group %s Found In Repository\n"), + basic_group_name)); + } + + try + { + PortableGroup::ObjectGroup_var group_var = + naming_manager_1->get_object_group_ref_from_name (basic_group_name); + + PortableGroup::Locations_var locations = + naming_manager_1->locations_of_members (group_var.in()); + + for (unsigned int i = 0; i < locations->length(); ++i) + { + const PortableGroup::Location & loc = locations[i]; + if (loc.length() > 0) { + + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("INFO: validating group member %C\n"), + loc[0].id.in())); + + try + { + + PortableGroup::Location location_name (1); + location_name.length (1); + location_name[0].id = CORBA::string_dup(loc[0].id.in()); + + CORBA::Object_var ior_var = + naming_manager_1->get_member_ref (group_var.in(), location_name); + + // Narrow it to a Basic object + Test::Basic_var basic = Test::Basic::_narrow (ior_var.in ()); + if (CORBA::is_nil (basic.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Unable to narrow from member ior from %C\n"), + loc[0].id.in()), + RC_ERROR); + } + + try + { + CORBA::String_var the_string = basic->get_string (); + + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("INFO: object group member at %C reports ") + ACE_TEXT ("%C\n"), + loc[0].id.in(), + the_string.in ())); + + if ( ACE_OS::strcmp (the_string.in (), loc[0].id.in()) != 0 ) { + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: object group member at %C reports %C\n\n"), + loc[0].id.in(), + the_string.in ()), + RC_ERROR); + } + } + catch (CORBA::Exception& ex) + { + ex._tao_print_exception ("ERROR: invoking get_string on Basic object.\n"); + return RC_ERROR; + } + } + catch (const PortableGroup::MemberNotFound&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Unable to find member location %C\n"), + loc[0].id.in()), + RC_ERROR); + } + } + } + + } + catch (const PortableGroup::ObjectGroupNotFound&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Unable to find group %C\n"), + basic_group_name), + RC_ERROR); + } + catch (const CORBA::Exception&) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Unable to list members for group %C\n"), + basic_group_name), + RC_ERROR); + } + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable To Resolve Name Manager Servers")); + return RC_ERROR; + } + + return RC_SUCCESS; +} + +//============================================================================== +// +//============================================================================== +/// Equivalence Name Test +int +do_equivalence_name_test ( + CORBA::ORB_ptr theOrb, + ACE_TCHAR *ns1ref, + ACE_TCHAR *ns2ref, + int c_breadth, + int c_depth, + int o_breadth) +{ + const int RC_SUCCESS = 0; + const int RC_ERROR = -1; + + CosNaming::NamingContext_var root_context_1; + CosNaming::NamingContext_var root_context_2; + int i; + + try { + + CORBA::ORB_var orb = CORBA::ORB::_duplicate(theOrb); + + if (CORBA::is_nil (orb.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid orb\n")), + RC_ERROR); + } + + if (CORBA::is_nil (ns1ref)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ns1\n")), + RC_ERROR); + } + + if (CORBA::is_nil (ns2ref)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ns2\n")), + RC_ERROR); + } + + CORBA::Object_var ns1obj = + orb->string_to_object (ACE_TEXT_ALWAYS_CHAR (ns1ref)); + + CORBA::Object_var ns2obj = + orb->string_to_object (ACE_TEXT_ALWAYS_CHAR (ns2ref)); + + if (CORBA::is_nil (ns1obj.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),ns1ref), + RC_ERROR); + } + + if (CORBA::is_nil (ns2obj.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),ns2ref), + RC_ERROR); + } + + root_context_1 = CosNaming::NamingContext::_narrow (ns1obj.in ()); + root_context_2 = CosNaming::NamingContext::_narrow (ns2obj.in ()); + + if (CORBA::is_nil (root_context_1.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),ns1ref), + RC_ERROR); + } + + if (CORBA::is_nil (root_context_2.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),ns2ref), + RC_ERROR); + } + + /// Make sure the two naming manager references point to different objects + if ( true == root_context_1->_stubobj ()->is_equivalent ( + root_context_2.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: ns1ref is equivalent to ns2ref\n")), + RC_ERROR); + } + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: ns1ref is not equivalent to ns2ref\n"))); + + int ns1_count = + root_context_1->_stubobj ()->base_profiles ().profile_count (); + + int ns2_count = + root_context_2->_stubobj ()->base_profiles ().profile_count (); + + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: ns1ref profile count: %d\n"), + ns1_count)); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: ns2ref profile count: %d\n"), + ns2_count)); + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("ERROR: Unable to resolve name servers")); + return RC_ERROR; + } + + // Create a bunch of objects in one context + // Note: strings to the naming service must be char, not wchar + try + { + // Bind one context level under root. + CosNaming::Name level1; + level1.length (1); + level1[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR("level1_context")); + CosNaming::NamingContext_var level1_context; + level1_context = root_context_1->bind_new_context (level1); + ACE_OS::thr_yield (); + + for (i=0; i<o_breadth; i++) + { + // Instantiate a dummy object and bind it under the new context. + My_Test_Object *impl1 = new My_Test_Object (i+1); + Test_Object_var obj1 = impl1->_this (); + impl1->_remove_ref (); + + level1.length (2); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("obj_%d"), i); + level1[1].id = CORBA::string_dup (wide_name); + root_context_1->bind (level1, obj1.in ()); + ACE_OS::thr_yield (); + + // See if the newly bound object is available in the + // replica + try { + CORBA::Object_var obj1_on_replica = root_context_2->resolve (level1); + } + catch (const CosNaming::NamingContext::NotFound& ex) + { + ex._tao_print_exception ("INFO: Unable to resolve object from replica.\n"); + + // Try again... + try { + CORBA::Object_var obj1_on_replica = root_context_2->resolve (level1); + // We did find the object on the replica, but only after a wait. + // This would be caused by a race condition to access the variable. + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("INFO: Object appeared after a short ") + ACE_TEXT ("wait.\n"))); + } + catch (const CosNaming::NamingContext::NotFound& second_ex) + { + second_ex._tao_print_exception ( + ACE_TEXT ("ERROR: It really is not there. Failing...\n")); + return RC_ERROR; + } + } + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to create a lot of objects")); + return RC_ERROR; + } + + // Create a deep context tree + try + { + CosNaming::NamingContext_var next_context = root_context_1; + for (i=0; i<c_depth; i++) + { + // Bind level1 context under root. + CosNaming::Name deep; + deep.length (1); + char deep_name[16]; + ACE_OS::sprintf(deep_name, ACE_TEXT_ALWAYS_CHAR ("deep_%d"), i); + deep[0].id = CORBA::string_dup (deep_name); + CosNaming::NamingContext_var deep_context; + deep_context = next_context->bind_new_context (deep); + ACE_OS::thr_yield (); + next_context = deep_context; + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to create deep context")); + return RC_ERROR; + } + + // Create a wide context tree + try + { + for (i=0; i<c_breadth; i++) + { + // Bind all level of context under root. + CosNaming::Name wide; + wide.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("wide_%d"), i); + wide[0].id = CORBA::string_dup (wide_name); + CosNaming::NamingContext_var wide_context; + wide_context = root_context_1->bind_new_context (wide); + ACE_OS::thr_yield (); + + try { + // Check if the new context is available in the replica + CORBA::Object_var obj1_on_replica = + root_context_2->resolve (wide); + + // Make sure it is a context + CosNaming::NamingContext_var nc = + CosNaming::NamingContext::_narrow (obj1_on_replica); + } + catch (const CosNaming::NamingContext::NotFound& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("INFO: Unable to resolve wide context object from ") + ACE_TEXT ("replica.\n")); + + // Try again to see if it just was a race condition + try { + + CORBA::Object_var obj1_on_replica = + root_context_2->resolve (wide); + + // We did find the object on the replica, but only after a wait. + // This would be caused by a race condition to access the variable. + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("INFO: Object appeared after a ") + ACE_TEXT ("short wait.\n"))); + } + catch (const CosNaming::NamingContext::NotFound& second_ex) + { + second_ex._tao_print_exception ( + ACE_TEXT ("ERROR: It really is not there. Failing...\n")); + return RC_ERROR; + } + } + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to create wide context")); + return RC_ERROR; + } + + // Delete three selected things, one from each tree + try { + // Remove the second to last object from the Naming Context + CosNaming::Name wide1; + wide1.length (2); + + wide1[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("level1_context")); + + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("obj_%d"), o_breadth-2); + wide1[1].id = CORBA::string_dup (wide_name); + root_context_1->unbind (wide1); + ACE_OS::thr_yield (); + + bool retried = false; + // Make sure it is gone from the replica + try { + CORBA::Object_var obj1_on_replica = root_context_2->resolve (wide1); + + // An exception should be thrown by the above or + // there is an error. This means the replica did + // not register the loss of the context. + ACE_ERROR (( LM_ERROR, + ACE_TEXT ("INFO: Unbound deep context not removed from ") + ACE_TEXT ("replica. Trying again...\n"))); + + retried = true; // Mark this so it can be reported in catch block. + obj1_on_replica = root_context_2->resolve (wide1); + + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: Unbound context not removed from ") + ACE_TEXT ("on retry\n")), + RC_ERROR); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Not on replica --- as it should be. + if (retried) // Was found on the retry + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("INFO: Was removed after short wait.\n"))); + } + + // Remove the second to last context from the wide root Naming Context + CosNaming::Name wide2; + wide2.length (1); + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("wide_%d"), c_breadth-2); + wide2[0].id = CORBA::string_dup (wide_name); + + CORBA::Object_var result_obj_ref = root_context_1->resolve (wide2); + + CosNaming::NamingContext_var result_object = + CosNaming::NamingContext::_narrow (result_obj_ref.in ()); + + if (CORBA::is_nil (result_object.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving wide") + ACE_TEXT (" context - nil object ref.\n")), + RC_ERROR); + } + + result_object->destroy(); + root_context_1->unbind (wide2); + ACE_OS::thr_yield (); + + // Remove the last context from the deep Naming Context + CosNaming::Name deep; + deep.length (c_depth); + char deep_name[16]; + for (i=0; i<c_depth; i++) + { + ACE_OS::sprintf(deep_name, ACE_TEXT_ALWAYS_CHAR ("deep_%d"), i); + deep[i].id = CORBA::string_dup (deep_name); + } + result_obj_ref = root_context_1->resolve (deep); + result_object = CosNaming::NamingContext::_narrow (result_obj_ref.in ()); + if (CORBA::is_nil (result_object.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving deep") + ACE_TEXT (" context - nil object ref.\n")), + RC_ERROR); + } + result_object->destroy(); + root_context_1->unbind (deep); + ACE_OS::thr_yield (); + + retried = false; + // Make sure it is gone from the replica + try { + CORBA::Object_var obj1_on_replica = root_context_2->resolve (deep); + + // An exception should be thrown by the above or + // there is an error. This means the replica did + // not register the loss of the context. + ACE_ERROR (( LM_ERROR, + ACE_TEXT ("INFO: Unbound deep context not removed from") + ACE_TEXT ("replica. Trying again...\n"))); + + retried = true; // Mark this so it can be reported in catch block. + obj1_on_replica = root_context_2->resolve (deep); + + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: Unbound context not removed from") + ACE_TEXT (" on retry\n")), + RC_ERROR); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Not on replica --- as it should be. + if (retried) // Was found on the retry + ACE_ERROR (( LM_ERROR, + ACE_TEXT ("INFO: Was removed after short wait.\n"))); + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to delete objects")); + return RC_ERROR; + } + + // Now use the other name server to access 3 objects next to the + // deleted objects and the 3 deleted objects + try + { + // Access the last object from the Naming Context + CosNaming::Name wide; + wide.length (2); + wide[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("level1_context")); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("obj_%d"), o_breadth-1); + wide[1].id = CORBA::string_dup (wide_name); + CORBA::Object_var result_obj_ref = root_context_2->resolve (wide); + Test_Object_var result_object = Test_Object::_narrow (result_obj_ref.in ()); + + if (CORBA::is_nil (result_object.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving object ") + ACE_TEXT ("from redundant server ") + ACE_TEXT ("- nil object ref.\n")), + RC_ERROR); + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to resolve object from redundant server")); + return RC_ERROR; + } + + try + { + // Access the deleted second to last object from the Naming Context + CosNaming::Name wide; + wide.length (2); + wide[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("level1_context")); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("obj_%d"), o_breadth-2); + wide[1].id = CORBA::string_dup (wide_name); + + CORBA::Object_var result_obj_ref = root_context_2->resolve (wide); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving object from ") + ACE_TEXT ("redundant server - deleted object found.\n")), + RC_ERROR); + } + catch (const CosNaming::NamingContext::NotFound& ex) + { + // expect exception since the context was deleted. + // Make sure the right exception reason is provided. + if (ex.why != CosNaming::NamingContext::missing_node) + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: Wrong exception returned during ") + ACE_TEXT ("resolve.\n")), + RC_ERROR); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Wrong exception type returned from resolve.\n")); + return RC_ERROR; + } + + try + { + // Access the last context from the wide Naming Context + CosNaming::Name wide; + wide.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("wide_%d"), c_breadth-1); + wide[0].id = CORBA::string_dup (wide_name); + CORBA::Object_var result_obj_ref = root_context_2->resolve (wide); + + CosNaming::NamingContext_var result_object = + CosNaming::NamingContext::_narrow (result_obj_ref.in ()); + + if (CORBA::is_nil (result_object.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving wide ") + ACE_TEXT ("context from redundant server ") + ACE_TEXT ("- nil object ref.\n")), + RC_ERROR); + } + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Expected exception + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( ACE_TEXT ("ERROR: Unexpected Exception ") + ACE_TEXT ("received.\n")); + return RC_ERROR; + } + + try + { + // Access the deleted second to last object from the Naming Context + CosNaming::Name wide; + wide.length (2); + char wide_name[16]; + ACE_OS::sprintf(wide_name, ACE_TEXT_ALWAYS_CHAR ("wide_%d"), c_breadth-2); + wide[0].id = CORBA::string_dup (wide_name); + CORBA::Object_var result_obj_ref = root_context_2->resolve (wide); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving wide context ") + ACE_TEXT ("from redundant server ") + ACE_TEXT ("- deleted object found.\n")), + RC_ERROR); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Expected exception + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( ACE_TEXT ("ERROR: Unexpected Exception ") + ACE_TEXT ("received.\n")); + return RC_ERROR; + } + + try + { + // Access the deleted last context from the deep Naming Context + CosNaming::Name deep; + deep.length (c_depth); + char deep_name[16]; + for (i=0; i<c_depth; i++) + { + ACE_OS::sprintf(deep_name, ACE_TEXT_ALWAYS_CHAR ("deep_%d"), i); + deep[i].id = CORBA::string_dup (deep_name); + } + CORBA::Object_var result_obj_ref = root_context_1->resolve (deep); + + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving deep context ") + ACE_TEXT ("from redundant server ") + ACE_TEXT ("- deleted object found.\n")), + RC_ERROR); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Expected exception + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unexpected Exception received resolving ") + ACE_TEXT ("deep cxt from redundant server.\n")); + return RC_ERROR; + } + + try + { + // Access the second to last object from the Naming Context + CosNaming::Name deep; + deep.length (c_depth-1); + char deep_name[16]; + for (i=0; i<c_depth-1; i++) + { + ACE_OS::sprintf(deep_name, ACE_TEXT_ALWAYS_CHAR ("deep_%d"), i); + deep[i].id = CORBA::string_dup (deep_name); + } + CORBA::Object_var result_obj_ref = root_context_1->resolve (deep); + + CosNaming::NamingContext_var result_object = + CosNaming::NamingContext::_narrow (result_obj_ref.in ()); + + if (CORBA::is_nil (result_object.in ())) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ERROR: Problems with resolving deep ") + ACE_TEXT ("context from redundant server ") + ACE_TEXT ("- nil object ref.\n")), + RC_ERROR); + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to resolve deep context from redundant server.")); + return RC_ERROR; + } + + return RC_SUCCESS; +} + + +/// Equivalence ObjectGroup Test +int +do_equivalence_objectgroup_test ( + CORBA::ORB_ptr theOrb, + ACE_TCHAR *nm1ref, + ACE_TCHAR *nm2ref, + int c_breadth, + int c_depth, + int o_breadth ) +{ + ACE_UNUSED_ARG (c_breadth); + ACE_UNUSED_ARG (c_depth); + ACE_UNUSED_ARG (o_breadth); + + const int RC_SUCCESS = 0; + const int RC_ERROR = -1; + int error_count = 0; + + + FT_Naming::NamingManager_var naming_manager_1; + FT_Naming::NamingManager_var naming_manager_2; + + try { + + CORBA::ORB_var orb = CORBA::ORB::_duplicate(theOrb); + if (CORBA::is_nil (orb.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid orb\n")), + RC_ERROR); + } + + if (CORBA::is_nil (nm1ref)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid nm1\n")), + RC_ERROR); + } + + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("INFO: nm1ref: %s\n"), + nm1ref)); + + CORBA::Object_var nm1obj = + orb->string_to_object (ACE_TEXT_ALWAYS_CHAR (nm1ref)); + + if (CORBA::is_nil (nm1obj.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"), + nm1ref), + RC_ERROR); + } + + naming_manager_1 = FT_Naming::NamingManager::_narrow (nm1obj.in ()); + if (CORBA::is_nil (naming_manager_1.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"), + nm1ref), + RC_ERROR); + } + + if (CORBA::is_nil (nm2ref)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid nm2\n")), + RC_ERROR); + } + + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("INFO: nm2ref: %s\n"), + nm2ref)); + + CORBA::Object_var nm2obj = + orb->string_to_object (ACE_TEXT_ALWAYS_CHAR (nm2ref)); + + if (CORBA::is_nil (nm2obj.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"), + nm2ref), + RC_ERROR); + } + + naming_manager_2 = FT_Naming::NamingManager::_narrow (nm2obj.in ()); + + if (CORBA::is_nil (naming_manager_2.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"), + nm2ref), + RC_ERROR); + } + + /// Make sure the two naming manager references point to different objects + if ( true == naming_manager_1->_stubobj ()->is_equivalent ( + naming_manager_2.in ())) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: nm1ref is equivalent to nm2ref\n")), + RC_ERROR); + } + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: nm1ref is not equivalent to nm2ref\n"))); + int nm1_count = + naming_manager_1->_stubobj ()->base_profiles ().profile_count (); + + int nm2_count = + naming_manager_2->_stubobj ()->base_profiles ().profile_count (); + + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: nm1ref profile count: %d\n"), + nm1_count)); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("INFO: nm2ref profile count: %d\n"), + nm2_count)); + + + /// Setup 1st NS_group_svc with 1st Naming Manager + NS_group_svc svc1; + if (RC_SUCCESS != svc1.set_orb (theOrb)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid orb\n")), + RC_ERROR); + } + + if (RC_SUCCESS != svc1.set_naming_manager (naming_manager_1)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"), + nm1ref), + RC_ERROR); + } + + /// Setup 2nd NS_group_svc with 2nd Naming Manager + NS_group_svc svc2; + if (RC_SUCCESS != svc2.set_orb (theOrb)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid orb\n")), + RC_ERROR); + } + + if (RC_SUCCESS != svc2.set_naming_manager (naming_manager_2)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: invalid ior <%s>\n"),nm2ref), + RC_ERROR); + } + + /// Now validate seamless operations between the two instances of NS_group + const char* policy = ACE_TEXT_ALWAYS_CHAR ("round"); + const char* test_group_1 = ACE_TEXT_ALWAYS_CHAR ("test_group_1"); + const char* test_group_2 = ACE_TEXT_ALWAYS_CHAR ("test_group_2"); + + if (RC_SUCCESS != svc1.group_create (test_group_1, policy)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: Unable to create %s\n"), + test_group_1), + RC_ERROR); + } + + if (RC_SUCCESS != svc2.group_create (test_group_2, policy)) + { + ACE_ERROR_RETURN (( LM_ERROR, + ACE_TEXT ("ERROR: Unable to create %s\n"), + test_group_2), + RC_ERROR); + } + + if (false == svc1.group_exist(test_group_1)) + { + ++error_count; + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("ERROR: Primary Not Able To Find Object Group ") + ACE_TEXT ("%s Created By Primary In Repository\n"), + test_group_1)); + } else { + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("INFO: Primary Found Object Group %s Created By ") + ACE_TEXT ("Primary In Repository\n"), + test_group_1)); + } + + if (false == svc2.group_exist(test_group_2)) + { + ++error_count; + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("ERROR: Backup Not Able To Find Object Group %s ") + ACE_TEXT ("Created By Backup In Repository\n"), + test_group_2)); + } else { + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("INFO: Backup Found Object Group %s Created By ") + ACE_TEXT ("Backup In Repository\n"), + test_group_2)); + } + + if (false == svc1.group_exist(test_group_2)) + { + ++error_count; + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("ERROR: Primary Not Able To Find Object Group %s ") + ACE_TEXT ("Created By Backup In Repository\n"), + test_group_2)); + } else { + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("INFO: Primary Found Object Group %s Created By ") + ACE_TEXT ("Backup In Repository\n"), + test_group_2)); + } + + if (false == svc2.group_exist(test_group_1)) + { + ++error_count; + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("ERROR: Backup Not Able To Find Object Group %s ") + ACE_TEXT ("Created By Primary In Repository\n"), + test_group_1)); + } else { + ACE_DEBUG (( LM_DEBUG, + ACE_TEXT ("INFO: Backup Found Object Group %s Created By ") + ACE_TEXT ("Primary In Repository\n"), + test_group_1)); + } + + } + catch (const CORBA::Exception& ex) + { + ++error_count; + ex._tao_print_exception ( + ACE_TEXT ("ERROR: Unable to resolve name manager servers")); + } + + return (error_count > 0) ? RC_ERROR : RC_SUCCESS; +} diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/GroupService/ObjectGroup_0 b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/GroupService/ObjectGroup_0 Binary files differnew file mode 100644 index 00000000000..0558ced7ed9 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/GroupService/ObjectGroup_0 diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/GroupService/ObjectGroup_global b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/GroupService/ObjectGroup_global new file mode 100644 index 00000000000..2f1465d1598 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/GroupService/ObjectGroup_global @@ -0,0 +1,3 @@ +1 +1 +0 diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/NameService/NameService b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/NameService/NameService new file mode 100644 index 00000000000..6b02ae41b97 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/NameService/NameService @@ -0,0 +1,5 @@ +7 +0 +0 +6 +wi
\ No newline at end of file diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/NameService/NameService_0 b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/NameService/NameService_0 new file mode 100644 index 00000000000..d09c35a22ba --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/NameService/NameService_0 @@ -0,0 +1,5 @@ +4 +0 +1 +5 +ob
\ No newline at end of file diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/NameService/NameService_1 b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/NameService/NameService_1 new file mode 100644 index 00000000000..5c1dc2a9185 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/NameService/NameService_1 @@ -0,0 +1,8 @@ +1 +0 +0 +6 +deep_1 +0 + +1
\ No newline at end of file diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/NameService/NameService_2 b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/NameService/NameService_2 new file mode 100644 index 00000000000..11367bed4cf --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/corrupt_data/NameService/NameService_2 @@ -0,0 +1,5 @@ +1 +0 +0 +6 +de
\ No newline at end of file diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/run_equivalence_test.pl b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/run_equivalence_test.pl new file mode 100755 index 00000000000..9fa2e86f51e --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/run_equivalence_test.pl @@ -0,0 +1,423 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::TestTarget; +use Cwd; + +#$ENV{ACE_TEST_VERBOSE} = "1"; + +my $startdir = getcwd(); +my $debug_level = '0'; +my $redirection_enabled = 0; + +foreach $i (@ARGV) { + if ($i eq '-debug') { + $debug_level = '10'; + $redirection_enabled = 0; + } +} + +my $server = PerlACE::TestTarget::create_target (1) || die "Create target 1 failed\n"; +my $client = PerlACE::TestTarget::create_target (2) || die "Create target 2 failed\n"; + + +# Variables for command-line arguments to client and server +# executables. +my $hostname = $server->HostName (); + +my $ns_orb_port1 = 10001 + $server->RandomPort (); +my $ns_orb_port2 = 10002 + $server->RandomPort (); + +my $ns_endpoint1 = "iiop://$hostname:$ns_orb_port1"; +my $ns_endpoint2 = "iiop://$hostname:$ns_orb_port2"; + +# References to primary naming service only +my $primary_default_init_ref = "-ORBDefaultInitRef corbaloc:iiop:$hostname:$ns_orb_port1"; + +# References to backup naming service only +my $backup_default_init_ref = "-ORBDefaultInitRef corbaloc:iiop:$hostname:$ns_orb_port2"; + +## Allow the user to determine where the persistence file will be located +## just in case the current directory is not suitable for locking. +## We can't change the name of the persistence file because that is not +## sufficient to work around locking problems for Tru64 when the current +## directory is NFS mounted from a system that does not properly support +## locking. +foreach my $possible ($ENV{TMPDIR}, $ENV{TEMP}, $ENV{TMP}) { + if (defined $possible && -d $possible) { + if (chdir($possible)) { + last; + } + } +} + +my $status = 0; +my $POSITIVE_TEST_RESULT = 0; +my $NEGATIVE_TEST_RESULT = 1; + +my $NSGROUP = $client->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_nsgroup"); +my $NSLIST = $client->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_nslist"); +my $NSADD = $client->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_nsadd"); +my $NSDEL = $client->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_nsdel"); + +sub cat_file($) +{ + my $file_name = shift; + if (-s $file_name ) # size of file is greater than zero + { + open TESTFILE, $file_name or die "Couldn't open file: $!"; + my @teststring = <TESTFILE>; # read in all of the file + print STDERR "\n@teststring\n"; + close TESTFILE; + } +} + +sub redirect_output() +{ + open (OLDOUT, ">&", \*STDOUT) or die "Can't dup STDOUT: $!"; + open (OLDERR, ">&", \*STDERR) or die "Can't dup STDERR: $!"; + open STDERR, '>', $client_stderr_file; + open STDOUT, '>', $client_stdout_file; +} + +sub restore_output() +{ + open (STDERR, ">&OLDERR") or die "Can't dup OLDERR: $!"; + open (STDOUT, ">&OLDOUT") or die "Can't dup OLDOUT: $!"; +} + +sub run_nsgroup ($$) +{ + my $args = shift; + my $expected_test_result = shift; + + my $arglist = "$args"; + + $NSGROUP->Arguments ($arglist); + + if ($redirection_enabled) { + redirect_output(); + } + + my $nsgroup_status = $NSGROUP->SpawnWaitKill ($client->ProcessStartWaitInterval()); + + if ($redirection_enabled) { + restore_output(); + } + + if ($nsgroup_status != $expected_test_result) { + my $time = localtime; + print STDERR "ERROR: nsgroup returned $nsgroup_status at $time\n"; + if ($redirection_enabled) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + $status = 1; + } +} + +sub run_nslist($$) +{ + my $args = shift; + my $expected_test_result = shift; + + $NSLIST->Arguments ($args); + + if ($redirection_enabled) { + redirect_output(); + } + + #tao_nslist --ns file://ns.ior + my $nslist_status = $NSLIST->SpawnWaitKill ($client->ProcessStartWaitInterval()); + + if ($redirection_enabled) { + restore_output(); + } + + if ($nslist_status != $expected_test_result) { + my $time = localtime; + print STDERR "ERROR: nslist returned $nslist_status at $time\n"; + if ($redirection_enabled) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + $status = 1; + } +} + +sub run_nsadd($$) +{ + my $args = shift; + my $expected_test_result = shift; + + $NSADD->Arguments ($args); + + if ($redirection_enabled) { + redirect_output(); + } + + #tao_nsadd --ns file://ns.ior --name iso --ctx + my $nsadd_status = $NSADD->SpawnWaitKill ($client->ProcessStartWaitInterval()); + + if ($redirection_enabled) { + restore_output(); + } + + if ($nsadd_status != $expected_test_result) { + my $time = localtime; + print STDERR "ERROR: nsadd returned $nsadd_status at $time\n"; + if ($redirection_enabled) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + $status = 1; + } +} + +sub run_nsdel($$) +{ + my $args = shift; + my $expected_test_result = shift; + + $NSDEL->Arguments ($args); + + if ($redirection_enabled) { + redirect_output(); + } + + #tao_nsdel --ns file://ns.ior --name iso --destroy + my $nsdel_status = $NSDEL->SpawnWaitKill ($client->ProcessStartWaitInterval()); + + if ($redirection_enabled) { + restore_output(); + } + + if ($nsdel_status != $expected_test_result) { + my $time = localtime; + print STDERR "ERROR: nsdel returned $nsdel_status at $time\n"; + if ($redirection_enabled) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + $status = 1; + } +} + +sub clean_persistence_dir($$) +{ + my $target = shift; + my $directory_name = shift; + + chdir $directory_name; + opendir(THISDIR, "."); + @allfiles = grep(!/^\.\.?$/, readdir(THISDIR)); + closedir(THISDIR); + foreach $tmp (@allfiles){ + $target->DeleteFile ($tmp); + } + chdir ".."; +} + +# Make sure that the directory to use to hold the naming contexts exists +# and is cleaned out +sub init_naming_context_directory($$) +{ + my $target = shift; + my $directory_name = shift; + + if ( ! -d $directory_name ) { + mkdir ($directory_name, 0777); + } else { + clean_persistence_dir ($target, $directory_name); + } +} + +my $name_dir = "NameService"; +my $group_dir = "GroupService"; +my $ns_replica_primary_iorfile = "$name_dir/ns_replica_primary.ior"; +my $ns_multi_iorfile = "ns_multi.ior"; +my $nm_multi_iorfile = "nm_multi.ior"; +my $ns_primary_iorfile = "ns_primary.ior"; +my $nm_primary_iorfile = "nm_primary.ior"; +my $ns_backup_iorfile = "ns_backup.ior"; +my $nm_backup_iorfile = "nm_backup.ior"; +my $stderr_file = "test.err"; +my $stdout_file = "test.out"; + +################################################################################ +# setup END block to cleanup after exit call +################################################################################ +END +{ + $server->DeleteFile ($ns_replica_primary_iorfile); + + $server->DeleteFile ($ns_multi_iorfile); + $server->DeleteFile ($nm_multi_iorfile); + $server->DeleteFile ($ns_primary_iorfile); + $server->DeleteFile ($nm_primary_iorfile); + $server->DeleteFile ($ns_backup_iorfile); + $server->DeleteFile ($nm_backup_iorfile); + + $client->DeleteFile ($ns_primary_iorfile); + $client->DeleteFile ($nm_primary_iorfile); + $client->DeleteFile ($ns_backup_iorfile); + $client->DeleteFile ($nm_backup_iorfile); + $client->DeleteFile ($stdout_file); + $client->DeleteFile ($stderr_file); + + if ( -d $name_dir ) { + print STDERR "INFO: removing <$name_dir>\n"; + clean_persistence_dir ($server, $name_dir); + rmdir ($name_dir); + } + + if ( -d $group_dir ) { + print STDERR "INFO: removing <$group_dir>\n"; + clean_persistence_dir ($server, $group_dir); + rmdir ($group_dir); + } +} + +################################################################################ +# Validate that a client can seamlessly invoke naming operations on either +# server instance. +################################################################################ +sub redundant_equivalency_test() +{ + my $previous_status = $status; + $status = 0; + + print_msg("Redundant Equivalency Test"); + + init_naming_context_directory ($server, $name_dir); + init_naming_context_directory ($server, $group_dir); + + # The file that is written by the primary when ready to start backup + my $server_primary_iorfile = $server->LocalFile ($ns_replica_primary_iorfile); + my $server_ns_multi_iorfile = $server->LocalFile ($ns_multi_iorfile); + my $server_nm_multi_iorfile = $server->LocalFile ($nm_multi_iorfile); + + my $server_ns_primary_iorfile = $server->LocalFile ($ns_primary_iorfile); + my $server_nm_primary_iorfile = $server->LocalFile ($nm_primary_iorfile); + my $server_ns_backup_iorfile = $server->LocalFile ($ns_backup_iorfile); + my $server_nm_backup_iorfile = $server->LocalFile ($nm_backup_iorfile); + + my $client_ns_primary_iorfile = $client->LocalFile ($ns_primary_iorfile); + my $client_nm_primary_iorfile = $client->LocalFile ($nm_primary_iorfile); + my $client_ns_backup_iorfile = $client->LocalFile ($ns_backup_iorfile); + my $client_nm_backup_iorfile = $client->LocalFile ($nm_backup_iorfile); + + my $client_stdout_file = $client->LocalFile ($stdout_file); + my $client_stderr_file = $client->LocalFile ($stderr_file); + + my $tao_ft_naming = "$ENV{TAO_ROOT}/orbsvcs/Naming_Service/tao_ft_naming"; + + # Run two Naming Servers + my $ns1_args = "--primary ". + "-ORBDebugLevel $debug_level " . + "-ORBListenEndPoints $ns_endpoint1 ". + "-o $server_ns_primary_iorfile ". + "-h $server_nm_primary_iorfile ". + "-r $name_dir ". + "-v $group_dir "; + + my $ns2_args = "--backup ". + "-ORBDebugLevel $debug_level " . + "-ORBListenEndPoints $ns_endpoint2 ". + "-o $server_ns_backup_iorfile ". + "-h $server_nm_backup_iorfile ". + "-c $server_ns_multi_iorfile ". + "-g $server_nm_multi_iorfile ". + "-r $name_dir ". + "-v $group_dir "; + + my $client_args = "--equivalence " . + "-ORBDebugLevel $debug_level " . + "-p file://$client_ns_primary_iorfile " . + "-q file://$client_ns_backup_iorfile " . + "-r file://$client_nm_primary_iorfile " . + "-s file://$client_nm_backup_iorfile " . + "-b 4 " . + "-d 4 "; + + my $client_prog = "$startdir/client"; + + + $NS1 = $server->CreateProcess ($tao_ft_naming, $ns1_args); + $NS2 = $server->CreateProcess ($tao_ft_naming, $ns2_args); + $CL = $client->CreateProcess ($client_prog, $client_args); + + $server->DeleteFile ($ns_primary_iorfile); + $NS1->Spawn (); + if ($server->WaitForFileTimed ($ns_primary_iorfile, + $server->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$server_primary_iorfile>\n"; + $NS1->Kill (); $NS1->TimedWait (1); + exit 1; + } + + $server->DeleteFile ($ns_multi_iorfile); + $NS2->Spawn (); + if ($server->WaitForFileTimed ($ns_multi_iorfile, + $server->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$server_ns_multi_iorfile>\n"; + $NS2->Kill (); $NS2->TimedWait (1); + $NS1->Kill (); $NS1->TimedWait (1); + exit 1; + } + + print_msg("INFO: Starting the client"); + $client_status = $CL->SpawnWaitKill ($client->ProcessStartWaitInterval()+5); + if ($client_status != 0) { + print STDERR "ERROR: client returned $client_status\n"; + $status = 1; + } + + + $server_status = $NS2->TerminateWaitKill ($server->ProcessStopWaitInterval()); + if ($server_status != 0) { + print STDERR "ERROR: server 2 returned $server_status\n"; + $status = 1; + } + + $server_status = $NS1->TerminateWaitKill ($server->ProcessStopWaitInterval()); + if ($server_status != 0) { + print STDERR "ERROR: server 1 returned $server_status\n"; + $status = 1; + } + + if ( $status == 0 ) { + $status = $previous_status; + } + + return $status; +} + +sub print_msg($) +{ + my $msg = shift; + my $bar = "==============================================================================="; + print STDERR "\n\n$bar\n$msg\n$bar\n"; +} + +sub show_result($$) +{ + my $test_result = shift; + my $test_name = shift; + + if ( 0 == $test_result ) { + print_msg("$test_name: SUCCESS"); + } else { + print_msg("$test_name: ERROR"); + } +} + +my $result = redundant_equivalency_test (); +show_result($result, "Redundant Equivalency Test"); + +exit $result; diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/run_failover_test.pl b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/run_failover_test.pl new file mode 100755 index 00000000000..ad2aeba4eac --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/run_failover_test.pl @@ -0,0 +1,416 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::TestTarget; +use Cwd; + +#$ENV{ACE_TEST_VERBOSE} = "1"; + +my $startdir = getcwd(); +my $debug_level = '0'; +my $redirection_enabled = 0; + +foreach $i (@ARGV) { + if ($i eq '-debug') { + $debug_level = '10'; + } + if ($i eq '-verbose') { + $redirection_enabled = 0; + } +} + +my $server = PerlACE::TestTarget::create_target (1) || die "Create target 1 failed\n"; +my $client = PerlACE::TestTarget::create_target (2) || die "Create target 2 failed\n"; + + +# Variables for command-line arguments to client and server +# executables. +my $hostname = $server->HostName (); + + +my $ns_orb_port1 = 10001 + $server->RandomPort (); +my $ns_orb_port2 = 10002 + $server->RandomPort (); + +my $ns_endpoint1 = "iiop://$hostname:$ns_orb_port1"; +my $ns_endpoint2 = "iiop://$hostname:$ns_orb_port2"; + + + +# References to both naming services +my $default_init_ref = "-ORBDefaultInitRef corbaloc:iiop:$hostname:$ns_orb_port1,iiop:$hostname:$ns_orb_port2"; + +# References to primary naming service only +my $primary_default_init_ref = "-ORBDefaultInitRef corbaloc:iiop:$hostname:$ns_orb_port1"; + +# References to backup naming service only +my $backup_default_init_ref = "-ORBDefaultInitRef corbaloc:iiop:$hostname:$ns_orb_port2"; + +## Allow the user to determine where the persistence file will be located +## just in case the current directory is not suitable for locking. +## We can't change the name of the persistence file because that is not +## sufficient to work around locking problems for Tru64 when the current +## directory is NFS mounted from a system that does not properly support +## locking. +foreach my $possible ($ENV{TMPDIR}, $ENV{TEMP}, $ENV{TMP}) { + if (defined $possible && -d $possible) { + if (chdir($possible)) { + last; + } + } +} + +my $status = 0; +my $POSITIVE_TEST_RESULT = 0; +my $NEGATIVE_TEST_RESULT = 1; + +my $NSGROUP = $client->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_nsgroup"); +my $NSLIST = $client->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_nslist"); +my $NSADD = $client->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_nsadd"); +my $NSDEL = $client->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_nsdel"); + +sub cat_file($) +{ + my $file_name = shift; + if (-s $file_name ) # size of file is greater than zero + { + open TESTFILE, $file_name or die "Couldn't open file: $!"; + my @teststring = <TESTFILE>; # read in all of the file + print STDERR "\n@teststring\n"; + close TESTFILE; + } +} + +sub redirect_output() +{ + open (OLDOUT, ">&", \*STDOUT) or die "Can't dup STDOUT: $!"; + open (OLDERR, ">&", \*STDERR) or die "Can't dup STDERR: $!"; + open STDERR, '>', $client_stderr_file; + open STDOUT, '>', $client_stdout_file; +} + +sub restore_output() +{ + open (STDERR, ">&OLDERR") or die "Can't dup OLDERR: $!"; + open (STDOUT, ">&OLDOUT") or die "Can't dup OLDOUT: $!"; +} + +sub run_nsgroup ($$) +{ + my $args = shift; + my $expected_test_result = shift; + + my $arglist = "$args"; + + $NSGROUP->Arguments ($arglist); + + if ($redirection_enabled) { + redirect_output(); + } + + my $nsgroup_status = $NSGROUP->SpawnWaitKill ($client->ProcessStartWaitInterval()); + + if ($redirection_enabled) { + restore_output(); + } + + if ($nsgroup_status != $expected_test_result) { + my $time = localtime; + print STDERR "ERROR: nsgroup returned $nsgroup_status at $time\n"; + if ($redirection_enabled) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + $status = 1; + } +} + +sub run_nslist($$) +{ + my $args = shift; + my $expected_test_result = shift; + + $NSLIST->Arguments ($args); + + if ($redirection_enabled) { + redirect_output(); + } + + #tao_nslist --ns file://ns.ior + my $nslist_status = $NSLIST->SpawnWaitKill ($client->ProcessStartWaitInterval()); + + if ($redirection_enabled) { + restore_output(); + } + + if ($nslist_status != $expected_test_result) { + my $time = localtime; + print STDERR "ERROR: nslist returned $nslist_status at $time\n"; + if ($redirection_enabled) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + $status = 1; + } +} + +sub run_nsadd($$) +{ + my $args = shift; + my $expected_test_result = shift; + + $NSADD->Arguments ($args); + + if ($redirection_enabled) { + redirect_output(); + } + + #tao_nsadd --ns file://ns.ior --name iso --ctx + my $nsadd_status = $NSADD->SpawnWaitKill ($client->ProcessStartWaitInterval()); + + if ($redirection_enabled) { + restore_output(); + } + + if ($nsadd_status != $expected_test_result) { + my $time = localtime; + print STDERR "ERROR: nsadd returned $nsadd_status at $time\n"; + if ($redirection_enabled) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + $status = 1; + } +} + +sub run_nsdel($$) +{ + my $args = shift; + my $expected_test_result = shift; + + $NSDEL->Arguments ($args); + + if ($redirection_enabled) { + redirect_output(); + } + + #tao_nsdel --ns file://ns.ior --name iso --destroy + my $nsdel_status = $NSDEL->SpawnWaitKill ($client->ProcessStartWaitInterval()); + + if ($redirection_enabled) { + restore_output(); + } + + if ($nsdel_status != $expected_test_result) { + my $time = localtime; + print STDERR "ERROR: nsdel returned $nsdel_status at $time\n"; + if ($redirection_enabled) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + $status = 1; + } +} + +sub clean_persistence_dir($$) +{ + my $target = shift; + my $directory_name = shift; + chdir $directory_name; + opendir(THISDIR, "."); + @allfiles = grep(!/^\.\.?$/, readdir(THISDIR)); + closedir(THISDIR); + foreach $tmp (@allfiles){ + $target->DeleteFile ($tmp); + } + chdir ".."; +} + +# Make sure that the directory to use to hold the naming contexts exists +# and is cleaned out +sub init_naming_context_directory($$) +{ + my $target = shift; + my $directory_name = shift; + + if ( ! -d $directory_name ) { + mkdir ($directory_name, 0777); + } else { + clean_persistence_dir ($target, $directory_name); + } +} + +my $name_dir = "NameService"; +my $group_dir = "GroupService"; +my $primary_iorfile = "$name_dir/ns_replica_primary.ior"; +my $nm_iorfile = "nm.ior"; +my $ns_iorfile = "ns.ior"; +my $stderr_file = "test.err"; +my $stdout_file = "test.out"; + +################################################################################ +# setup END block to cleanup after exit call +################################################################################ +END +{ + $server->DeleteFile($primary_iorfile); + $server->DeleteFile($nm_iorfile); + $server->DeleteFile($ns_iorfile); + $client->DeleteFile ($stdout_file); + $client->DeleteFile ($stderr_file); + + if ( -d $name_dir ) { + print STDERR "INFO: removing <$name_dir>\n"; + clean_persistence_dir ($server, $name_dir); + rmdir ($name_dir); + } + + if ( -d $group_dir ) { + print STDERR "INFO: removing <$group_dir>\n"; + clean_persistence_dir ($server, $group_dir); + rmdir ($group_dir); + } + +} + +################################################################################ +# Validate that a client can seamlessly connect to the alternate server of a +# server naming server pair after the other server has been terminated. +################################################################################ +sub failover_test() +{ + my $previous_status = $status; + $status = 0; + + # The file that is written by the primary when ready to start backup + my $server_primary_iorfile = $server->LocalFile ($primary_iorfile); + my $server_nm_iorfile = $server->LocalFile ($nm_iorfile); + my $server_ns_iorfile = $server->LocalFile ($ns_iorfile); + my $client_stdout_file = $client->LocalFile ($stdout_file); + my $client_stderr_file = $client->LocalFile ($stderr_file); + + print_msg("Failover Test"); + init_naming_context_directory ($server, $name_dir ); + init_naming_context_directory ($server, $group_dir ); + + # Run two Naming Servers + my $ns1_args = "--primary ". + "-ORBDebugLevel $debug_level ". + "-ORBListenEndPoints $ns_endpoint1 ". + "-m 0 ". + "-r $name_dir ". + "-v $group_dir"; + + my $ns2_args = "--backup ". + "-ORBDebugLevel $debug_level ". + "-ORBListenEndPoints $ns_endpoint2 ". + "-c $server_ns_iorfile ". + "-g $server_nm_iorfile ". + "-m 0 ". + "-r $name_dir ". + "-v $group_dir"; + + my $tao_ft_naming = "$ENV{TAO_ROOT}/orbsvcs/Naming_Service/tao_ft_naming"; + + my $client_args = "--failover " . + "-ORBDebugLevel $debug_level " . + "-p file://$server_ns_iorfile " . + "-r file://$server_nm_iorfile " . + "-b 4 " . + "-d 4 " ; + + my $client_prog = "$startdir/client"; + + $NS1 = $server->CreateProcess ($tao_ft_naming, $ns1_args); + $NS2 = $server->CreateProcess ($tao_ft_naming, $ns2_args); + $CL = $client->CreateProcess ($client_prog, $client_args); + + $server->DeleteFile ($primary_iorfile); + $server->DeleteFile ($ns_iorfile); + $server->DeleteFile ($nm_iorfile); + + print_msg("INFO: Starting the primary"); + $NS1->Spawn (); + if ($server->WaitForFileTimed ($primary_iorfile, + $server->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$server_primary_iorfile>\n"; + $NS1->Kill (); $NS1->TimedWait (1); + exit 1; + } + + print_msg("INFO: Starting the backup"); + $NS2->Spawn (); + if ($server->WaitForFileTimed ($ns_iorfile, + $server->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$server_ns_iorfile>\n"; + $NS2->Kill (); $NS2->TimedWait (1); + $NS1->Kill (); $NS1->TimedWait (1); + exit 1; + } + + print_msg("INFO: Starting the client"); + $CL->Spawn (); + + $server_status = $NS1->TerminateWaitKill ($server->ProcessStopWaitInterval()); + if ($server_status != 0) { + print STDERR "ERROR: server 1 returned $server_status\n"; + $status = 1; + } + + print_msg("INFO: restart primary server"); + $NS1->Spawn (); + + sleep(5); + + $client_status = $CL->TerminateWaitKill ($client->ProcessStopWaitInterval()); + if ($client_status != 0) { + print STDERR "ERROR: client returned $client_status\n"; + $status = 1; + } + + $server_status = $NS2->TerminateWaitKill ($server->ProcessStopWaitInterval()); + if ($server_status != 0) { + print STDERR "ERROR: server 2 returned $server_status\n"; + $status = 1; + } + + $server_status = $NS1->TerminateWaitKill ($server->ProcessStopWaitInterval()); + if ($server_status != 0) { + print STDERR "ERROR: server 1 returned $server_status\n"; + $status = 1; + } + + if ( $status == 0 ) { + $status = $previous_status; + } + + return $status; +} + +sub print_msg($) +{ + my $msg = shift; + my $bar = "==============================================================================="; + print STDERR "\n\n$bar\n$msg\n$bar\n"; +} + +sub show_result($$) +{ + my $test_result = shift; + my $test_name = shift; + + if ( 0 == $test_result ) { + print_msg("$test_name: SUCCESS"); + } else { + print_msg("$test_name: ERROR"); + } +} + +my $result = failover_test (); +show_result($result, "Failover Test"); + +exit $result; diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/run_persistence_test.pl b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/run_persistence_test.pl new file mode 100755 index 00000000000..c71653cfec1 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/run_persistence_test.pl @@ -0,0 +1,652 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::TestTarget; +use Cwd; +use File::Compare; +use File::Copy; + +#$ENV{ACE_TEST_VERBOSE} = "1"; + +my $startdir = getcwd(); +my $debug_level = '0'; +my $redirection_enabled = 0; + +foreach $i (@ARGV) { + if ($i eq '-debug') { + $debug_level = '10'; + } + if ($i eq '-verbose') { + $redirection_enabled = 0; + } + +} + +my $server = PerlACE::TestTarget::create_target (1) || die "Create target 1 failed\n"; +my $client = PerlACE::TestTarget::create_target (2) || die "Create target 2 failed\n"; +my $server2 = PerlACE::TestTarget::create_target (3) || die "Create target 3 failed\n"; + + + +# Variables for command-line arguments to client and server +# executables. + +my $stdout_file = "test.out"; +my $stderr_file = "test.err"; +my $client_stdout_file = $client->LocalFile ($stdout_file); +my $client_stderr_file = $client->LocalFile ($stderr_file); + +my $status = 0; +my $POSITIVE_TEST_RESULT = 0; +my $NEGATIVE_TEST_RESULT = 1; + +my $NSGROUP = $client->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_nsgroup"); +my $NSLIST = $client->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_nslist"); +my $NSADD = $client->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_nsadd"); +my $NSDEL = $client->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_nsdel"); + +## Allow the user to determine where the persistence file will be located +## just in case the current directory is not suitable for locking. +## We can't change the name of the persistence file because that is not +## sufficient to work around locking problems for Tru64 when the current +## directory is NFS mounted from a system that does not properly support +## locking. +foreach my $possible ($ENV{TMPDIR}, $ENV{TEMP}, $ENV{TMP}) { + if (defined $possible && -d $possible) { + if (chdir($possible)) { + last; + } + } +} + +sub cat_file($) +{ + my $file_name = shift; + if (-s $file_name ) # size of file is greater than zero + { + open TESTFILE, $file_name or die "Couldn't open file: $!"; + my @teststring = <TESTFILE>; # read in all of the file + print STDERR "\n@teststring\n"; + close TESTFILE; + } +} + +sub redirect_output() +{ + open (OLDOUT, ">&", \*STDOUT) or die "Can't dup STDOUT: $!"; + open (OLDERR, ">&", \*STDERR) or die "Can't dup STDERR: $!"; + open STDERR, '>', $client_stderr_file; + open STDOUT, '>', $client_stdout_file; +} + +sub restore_output() +{ + open (STDERR, ">&OLDERR") or die "Can't dup OLDERR: $!"; + open (STDOUT, ">&OLDOUT") or die "Can't dup OLDOUT: $!"; +} + +sub compare_file_with_backup($) +{ + my $file = shift; + my $backup = $file . ".bak"; + unless (-e $backup) { + print STDERR "ERROR: Backup file $backup does not exist\n"; + return 1; + } + my $result = compare ($file, $backup); + if ($result != 0) { + print STDERR "ERROR: Backup file $backup does not agree with $file\n"; + } + return $result; +} + +sub run_nsgroup ($$) +{ + my $args = shift; + my $expected_test_result = shift; + + my $arglist = "$args"; + + $NSGROUP->Arguments ($arglist); + + if ($redirection_enabled) { + redirect_output(); + } + + my $nsgroup_status = $NSGROUP->SpawnWaitKill ($client->ProcessStartWaitInterval()); + + if ($redirection_enabled) { + restore_output(); + } + + if ($nsgroup_status != $expected_test_result) { + my $time = localtime; + print STDERR "ERROR: nsgroup returned $nsgroup_status at $time\n"; + if ($redirection_enabled) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + $status = 1; + } +} + +sub run_nslist($$) +{ + my $args = shift; + my $expected_test_result = shift; + + $NSLIST->Arguments ($args); + + if ($redirection_enabled) { + redirect_output(); + } + + #tao_nslist --ns file://ns.ior + my $nslist_status = $NSLIST->SpawnWaitKill ($client->ProcessStartWaitInterval()); + + if ($redirection_enabled) { + restore_output(); + } + + if ($nslist_status != $expected_test_result) { + my $time = localtime; + print STDERR "ERROR: nslist returned $nslist_status at $time\n"; + if ($redirection_enabled) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + $status = 1; + } +} + +sub run_nsadd($$) +{ + my $args = shift; + my $expected_test_result = shift; + + $NSADD->Arguments ($args); + + if ($redirection_enabled) { + redirect_output(); + } + + #tao_nsadd --ns file://ns.ior --name iso --ctx + my $nsadd_status = $NSADD->SpawnWaitKill ($client->ProcessStartWaitInterval()); + + if ($redirection_enabled) { + restore_output(); + } + + if ($nsadd_status != $expected_test_result) { + my $time = localtime; + print STDERR "ERROR: nsadd returned $nsadd_status at $time\n"; + if ($redirection_enabled) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + $status = 1; + } +} + +sub run_nsdel($$) +{ + my $args = shift; + my $expected_test_result = shift; + + $NSDEL->Arguments ($args); + + if ($redirection_enabled) { + redirect_output(); + } + + #tao_nsdel --ns file://ns.ior --name iso --destroy + my $nsdel_status = $NSDEL->SpawnWaitKill ($client->ProcessStartWaitInterval()); + + if ($redirection_enabled) { + restore_output(); + } + + if ($nsdel_status != $expected_test_result) { + my $time = localtime; + print STDERR "ERROR: nsdel returned $nsdel_status at $time\n"; + if ($redirection_enabled) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + $status = 1; + } +} + +sub clean_persistence_dir($$) +{ + my $target = shift; + my $directory_name = shift; + + chdir $directory_name; + opendir(THISDIR, "."); + @allfiles = grep(!/^\.\.?$/, readdir(THISDIR)); + closedir(THISDIR); + foreach $tmp (@allfiles){ + $target->DeleteFile ($tmp); + } + chdir ".."; +} + +# Make sure that the directory to use to hold the naming contexts exists +# and is cleaned out +sub init_persistence_dir($$) +{ + my $target = shift; + my $directory_name = shift; + + if ( ! -d $directory_name ) { + mkdir ($directory_name, 0777); + } else { + clean_persistence_dir ($target, $directory_name); + } +} + +my $name_dir = "NameService"; +my $group_dir = "GroupService"; +my $nm_iorfile = "nm.ior"; +my $ns_iorfile = "ns.ior"; +my $sv_iorfile = "obj.ior"; +my $ns_ref = "--ns file://$ns_iorfile"; +my $sv2_iorfile = $server2->LocalFile ($sv_iorfile); + + + + +################################################################################ +# setup END block to cleanup after exit call +################################################################################ +END +{ + $server->DeleteFile ($ns_iorfile); + $server->DeleteFile ($nm_iorfile); + $client->DeleteFile ($nm_iorfile); + $client->DeleteFile ($stdout_file); + $client->DeleteFile ($stderr_file); + $server2->DeleteFile($sv_iorfile); + + if ( -d $name_dir ) { + print STDERR "INFO: removing <$name_dir>\n"; + clean_persistence_dir ($server, $name_dir); + rmdir ($name_dir); + } + + if ( -d $group_dir ) { + print STDERR "INFO: removing <$group_dir>\n"; + clean_persistence_dir ($server, $group_dir); + rmdir ($group_dir); + } +} + +################################################################################ +# Validate that repository data written by the name service is available upon +# startup. +################################################################################ +sub persistence_test () +{ + my $previous_status = $status; + $status = 0; + + my $hostname = $server->HostName (); + my $ns_orb_port1 = 10001 + $server->RandomPort (); + my $ns_endpoint1 = "iiop://$hostname:$ns_orb_port1"; + my $default_init_ref = "-ORBDefaultInitRef corbaloc:iiop:$hostname:$ns_orb_port1"; + my $client_nm_iorfile = $client->LocalFile ($nm_iorfile); + + print_msg("Persistence Test"); + init_persistence_dir ($server, $name_dir ); + init_persistence_dir ($server, $group_dir ); + + my $ns_args = "-ORBListenEndPoints $ns_endpoint1 ". + "-ORBDebugLevel $debug_level " . + "-g $nm_iorfile ". + "-o $ns_iorfile ". + "-v $group_dir ". + "-u $name_dir "; + + my $tao_ft_naming = "$ENV{TAO_ROOT}/orbsvcs/Naming_Service/tao_ft_naming"; + + my $client1_args = "--persistence " . + "--create " . + "-ORBDebugLevel $debug_level " . + "-p corbaloc:iiop:$hostname:$ns_orb_port1/NameService " . + "-r corbaloc:iiop:$hostname:$ns_orb_port1/NamingManager " . + "-b 4 " . + "-d 4 "; + + my $client2_args = "--persistence " . + "--validate " . + "-ORBDebugLevel $debug_level " . + "-p corbaloc:iiop:$hostname:$ns_orb_port1/NameService " . + "-r corbaloc:iiop:$hostname:$ns_orb_port1/NamingManager " . + "-b 4 " . + "-d 4 "; + + my $client_prog = "$startdir/client"; + + + ##1. Run one instance of tao_ft_naming service + $NS1 = $server->CreateProcess ($tao_ft_naming, $ns_args); + $CL1 = $client->CreateProcess ($client_prog, $client1_args); + $CL2 = $client->CreateProcess ($client_prog, $client2_args); + + + my $server2_args = "-ORBdebuglevel $debug_level " . + "$default_init_ref ". + "-o $sv2_iorfile "; + + $SV2 = $server2->CreateProcess ("$startdir/server", $server2_args); + + $server->DeleteFile ($ns_iorfile); + $NS1->Spawn (); + if ($server->WaitForFileTimed ($ns_iorfile, + $server->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$ns_iorfile>\n"; + $NS1->Kill (); $NS1->TimedWait (1); + exit 1; + } + + ##2. Create new contexts and new object groups + print_msg("INFO: starting test server"); + $server_status = $SV2->Spawn (); + if ($server_status != 0) { + print STDERR "ERROR: server returned $server_status\n"; + exit 1; + } + if ($server2->WaitForFileTimed ($sv_iorfile, + $server2->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$sv_iorfile>\n"; + $SV2->Kill (); $SV2->TimedWait (1); + exit 1; + } + + ##3. Creation additional contexts and object groups and verify + print_msg("INFO: Starting client1"); + $client_status = $CL1->SpawnWaitKill ($client->ProcessStartWaitInterval()); + if ($client_status != 0) { + print STDERR "ERROR: client1 returned $client_status\n"; + $status = 1; + } + + ##4. Kill the tao_ft_naming server + print_msg("Kill the tao_ft_naming server"); + $server_status = $NS1->TerminateWaitKill ($server->ProcessStopWaitInterval()); + if ($server_status != 0) { + print STDERR "ERROR: server 1 returned $server_status\n"; + $status = 1; + } + + ##5. Start a new instance of the tao_ft_naming server + print_msg("Start a new instance of the tao_ft_naming server"); + $server->DeleteFile ($ns_iorfile); + $NS1->Spawn (); + if ($server->WaitForFileTimed ($ns_iorfile, + $server->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$ns_iorfile>\n"; + $NS1->Kill (); $NS1->TimedWait (1); + $status = 1; + } + + ##6. Verify the new name, object group and member are in the tao_ft_naming repository. + print_msg("Verify the new name, object group and member are in the tao_ft_naming repository"); + print_msg("INFO: Starting client2"); + $client_status = $CL2->SpawnWaitKill ($client->ProcessStartWaitInterval()); + if ($client_status != 0) { + print STDERR "ERROR: client2 returned $client_status\n"; + $status = 1; + } + + print_msg("INFO: terminating test server"); + $server_status = $SV2->TerminateWaitKill ($server2->ProcessStopWaitInterval()); + if ($server_status != 0) { + print STDERR "ERROR: server returned $server_status\n"; + $status = 1; + } + + $server_status = $NS1->TerminateWaitKill ($server->ProcessStopWaitInterval()); + if ($server_status != 0) { + print STDERR "ERROR: server 1 returned $server_status\n"; + $status = 1; + } + + if ( $status == 0 ) { + $status = $previous_status; + } + + return $status; +} + +################################################################################ +# Validate that when a corrupt persistent file is read that the contents of the +# backup file is used instead. +################################################################################ +sub backup_restore_test () +{ + + my $num_child_contexts = 8; + my $num_object_groups = 1; + + my $previous_status = $status; + $status = 0; + + my $hostname = $server->HostName (); + my $ns_orb_port1 = 10001 + $server->RandomPort (); + my $ns_endpoint1 = "iiop://$hostname:$ns_orb_port1"; + my $default_init_ref = "-ORBDefaultInitRef corbaloc:iiop:$hostname:$ns_orb_port1"; + my $client_nm_iorfile = $client->LocalFile ($nm_iorfile); + + print_msg("Backup/Restore Test"); + init_persistence_dir ($server, $name_dir ); + init_persistence_dir ($server, $group_dir ); + + my $ns_args = "-ORBListenEndPoints $ns_endpoint1 ". + "-ORBDebugLevel $debug_level " . + "-g $nm_iorfile ". + "-o $ns_iorfile ". + "-v $group_dir ". + "-u $name_dir "; + + my $tao_ft_naming = "$ENV{TAO_ROOT}/orbsvcs/Naming_Service/tao_ft_naming"; + + my $client1_args = "--persistence " . + "--create " . + "-ORBDebugLevel $debug_level " . + "-p corbaloc:iiop:$hostname:$ns_orb_port1/NameService " . + "-r corbaloc:iiop:$hostname:$ns_orb_port1/NamingManager " . + "-b 4 " . + "-d 4 "; + + my $client2_args = "--persistence " . + "--validate " . + "-ORBDebugLevel $debug_level " . + "-p corbaloc:iiop:$hostname:$ns_orb_port1/NameService " . + "-r corbaloc:iiop:$hostname:$ns_orb_port1/NamingManager " . + "-b 4 " . + "-d 4 "; + + my $client_prog = "$startdir/client"; + + + ##1. Run one instance of tao_ft_naming service + $NS1 = $server->CreateProcess ($tao_ft_naming, $ns_args); + $CL1 = $client->CreateProcess ($client_prog, $client1_args); + $CL2 = $client->CreateProcess ($client_prog, $client2_args); + + + my $server2_args = "-ORBdebuglevel $debug_level " . + "$default_init_ref ". + "-o $sv2_iorfile "; + + $SV2 = $server2->CreateProcess ("$startdir/server", $server2_args); + + $server->DeleteFile ($ns_iorfile); + $NS1->Spawn (); + if ($server->WaitForFileTimed ($ns_iorfile, + $server->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$ns_iorfile>\n"; + $NS1->Kill (); $NS1->TimedWait (1); + exit 1; + } + + ##2. Create new contexts and new object groups + print_msg("INFO: starting test server"); + $server_status = $SV2->Spawn (); + if ($server_status != 0) { + print STDERR "ERROR: server returned $server_status\n"; + exit 1; + } + if ($server2->WaitForFileTimed ($sv_iorfile, + $server2->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$sv_iorfile>\n"; + $SV2->Kill (); $SV2->TimedWait (1); + exit 1; + } + + ##3. Creation additional contexts and object groups and verify + print_msg("INFO: Starting client1"); + $client_status = $CL1->SpawnWaitKill ($client->ProcessStartWaitInterval()); + if ($client_status != 0) { + print STDERR "ERROR: client1 returned $client_status\n"; + $status = 1; + } + + ##4. Kill the tao_ft_naming server + print_msg("Kill the tao_ft_naming server"); + $server_status = $NS1->TerminateWaitKill ($server->ProcessStopWaitInterval()); + if ($server_status != 0) { + print STDERR "ERROR: server 1 returned $server_status\n"; + $status = 1; + } + + ##5. Verify that backup files are created + + print_msg("Verifying naming context backup files"); + $file = $name_dir . "/NameService"; + if (compare_file_with_backup ($file) != 0) { + $status = 1; + } + for ($i = 0; $i < $num_child_contexts; $i++) { + $file = $name_dir . "/NameService_$i"; + if (compare_file_with_backup ($file) != 0) { + $status = 1; + } + } + + print_msg("Verifying object group backup files"); + $file = $group_dir . "/ObjectGroup_global"; + if (compare_file_with_backup ($file) != 0) { + $status = 1; + } + for ($i = 0; $i < $num_object_groups; $i++) { + $file = $group_dir . "/ObjectGroup_$i"; + if (compare_file_with_backup ($file) != 0) { + $status = 1; + } + } + + ##6. Replace some of the data files with corrupt files + print_msg("Replace data files with corrupt files"); + my $corrupt_data_dir = $startdir . "/corrupt_data/"; + + my $corrupt_name_dir = $corrupt_data_dir . $name_dir . "/"; + opendir(NAMEDIR, $corrupt_name_dir); + @allfiles = grep(/^NameService/, readdir(NAMEDIR)); + closedir(NAMEDIR); + foreach $file (@allfiles) { + copy ($corrupt_name_dir . $file, $name_dir . "/" . $file) or die "Copy failed: $!\n"; + } + + my $corrupt_group_dir = $corrupt_data_dir . $group_dir . "/"; + opendir(GROUPDIR, $corrupt_group_dir); + @allfiles = grep(/^ObjectGroup/, readdir(GROUPDIR)); + closedir(GROUPDIR); + foreach $file (@allfiles) { + copy ($corrupt_group_dir . $file, $group_dir . "/" . $file) or die "Copy failed: $!\n"; + } + + ##7. Start a new instance of the tao_ft_naming server + print_msg("Start a new instance of the tao_ft_naming server and then running client 2"); + $server->DeleteFile ($ns_iorfile); + # Redirect output so that expected error messages are not interpreted as + # test failure and rely instead of return status. + redirect_output(); + my $restore_status = 0; + $NS1->Spawn (); + if ($server->WaitForFileTimed ($ns_iorfile, + $server->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$ns_iorfile>\n"; + $NS1->Kill (); $NS1->TimedWait (1); + $status = 1; + $restorestatus = 1; + } + + ##8. Verify the new name, object group and member are in the tao_ft_naming repository. + print_msg("Verify the backup files are used when the corrupt files are read"); + print_msg("INFO: Starting client2"); + $client_status = $CL2->SpawnWaitKill ($client->ProcessStartWaitInterval()); + restore_output(); + if ($client_status != 0) { + print STDERR "ERROR: client2 returned $client_status\n"; + $status = 1; + $restorestatus = 1; + } + + if ($restore_status == 1) { + cat_file($client_stderr_file); + cat_file($client_stdout_file); + } + + print_msg("INFO: terminating test server"); + $server_status = $SV2->TerminateWaitKill ($server2->ProcessStopWaitInterval()); + if ($server_status != 0) { + print STDERR "ERROR: server returned $server_status\n"; + $status = 1; + } + + $server_status = $NS1->TerminateWaitKill ($server->ProcessStopWaitInterval()); + if ($server_status != 0) { + print STDERR "ERROR: server 1 returned $server_status\n"; + $status = 1; + } + + if ( $status == 0 ) { + $status = $previous_status; + } + + return $status; +} + +sub print_msg($) +{ + my $msg = shift; + my $bar = "==============================================================================="; + print STDERR "\n\n$bar\n$msg\n$bar\n"; +} + +sub show_result($$) +{ + my $test_result = shift; + my $test_name = shift; + + if ( 0 == $test_result ) { + print_msg("$test_name: SUCCESS"); + } else { + print_msg("$test_name: ERROR"); + } +} + +my $result = persistence_test (); +my $result = backup_restore_test (); + +show_result($result, "Persistence Test"); + +exit $result; diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/run_test.pl b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/run_test.pl new file mode 100755 index 00000000000..1f2a652df81 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/run_test.pl @@ -0,0 +1,44 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::TestTarget; +use Cwd; + + +my @list=("run_failover_test.pl", + "run_persistence_test.pl", + "run_equivalence_test.pl"); + +my $status = 0; + +my $debug_option = ''; + +foreach $i (@ARGV) { + if ($i eq '-debug') { + $debug_option = '-debug'; + } +} + +for $cmd (@list) { + if (-f $cmd) { + if (system ("perl $cmd $debug_option") != 0) { + $status = 1; + } + } else { + print STDERR "ERROR: Can't find $cmd\n"; + } +} +my $test_label = "FT_Naming FaultTolerant"; + +if ($status != 0) { + print STDERR "ERROR: One or more $test_label tests Failed\n"; +} else { + print STDERR "INFO: All $test_label tests report OK\n"; +} + +exit $status; diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/server.cpp b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/server.cpp new file mode 100644 index 00000000000..57b661e1bd6 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/server.cpp @@ -0,0 +1,121 @@ +// $Id$ + +#include "LB_server.h" +#include "Basic.h" + +int +ACE_TMAIN(int argc, ACE_TCHAR *argv[]) +{ + try + { + const char *location1 = ACE_TEXT_ALWAYS_CHAR ("location1"); + const char *location2 = ACE_TEXT_ALWAYS_CHAR ("location2"); + const char *location3 = ACE_TEXT_ALWAYS_CHAR ("location3"); + const char *location4 = ACE_TEXT_ALWAYS_CHAR ("location4"); + const char *location5 = ACE_TEXT_ALWAYS_CHAR ("location5"); + const char *location6 = ACE_TEXT_ALWAYS_CHAR ("location6"); + + LB_server lb_server (argc, argv); + + if (lb_server.start_orb_and_poa () != 0) + return 1; + + if (lb_server.create_object_group () != 0) + return 1; + + CosNaming::Name name (1); + name.length (1); + name[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("basic_name")); + try { + (lb_server.name_svc ())->rebind (name, lb_server.object_group ()); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Unable to bind object group in name service.\n")); + return 1; + } + + Basic *basic_servant1; + Basic *basic_servant2; + Basic *basic_servant3; + Basic *basic_servant4; + Basic *basic_servant5; + Basic *basic_servant6; + + ACE_NEW_RETURN (basic_servant1, + Basic (lb_server.object_group (), + lb_server.naming_manager (), + lb_server.orb (), + location1), + 1); + PortableServer::ServantBase_var owner_transfer1(basic_servant1); + + ACE_NEW_RETURN (basic_servant2, + Basic (lb_server.object_group (), + lb_server.naming_manager (), + lb_server.orb (), + location2), + 1); + PortableServer::ServantBase_var owner_transfer2(basic_servant2); + + ACE_NEW_RETURN (basic_servant3, + Basic (lb_server.object_group (), + lb_server.naming_manager (), + lb_server.orb (), + location3), + 1); + PortableServer::ServantBase_var owner_transfer3(basic_servant3); + + ACE_NEW_RETURN (basic_servant4, + Basic (lb_server.object_group (), + lb_server.naming_manager (), + lb_server.orb (), + location4), + 1); + PortableServer::ServantBase_var owner_transfer4(basic_servant4); + + ACE_NEW_RETURN (basic_servant5, + Basic (lb_server.object_group (), + lb_server.naming_manager (), + lb_server.orb (), + location5), + 1); + PortableServer::ServantBase_var owner_transfer5(basic_servant5); + + ACE_NEW_RETURN (basic_servant6, + Basic (lb_server.object_group (), + lb_server.naming_manager (), + lb_server.orb (), + location6), + 1); + PortableServer::ServantBase_var owner_transfer6(basic_servant6); + + if (lb_server.register_servant (basic_servant1, location1) == -1 + || lb_server.register_servant (basic_servant2, location2) == -1 + || lb_server.register_servant (basic_servant3, location3) == -1 + || lb_server.register_servant (basic_servant4, location4) == -1 + || lb_server.register_servant (basic_servant5, location5) == -1 + || lb_server.register_servant (basic_servant6, location6) == -1) + { + (void) lb_server.destroy (); + return 1; + } + + lb_server.orb ()->run (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) server - event loop finished\n"))); + + if (lb_server.destroy () == -1) + return 1; + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("lb_server exception")); + return 1; + } + + return 0; +} diff --git a/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/test_object.idl b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/test_object.idl new file mode 100644 index 00000000000..4737f6dc6c8 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/FaultTolerant/test_object.idl @@ -0,0 +1,11 @@ +// $Id$ + +interface Test_Object +{ + // = TITLE + // This is a simple interface that tests the Naming Service. + + attribute short id; + // This provides an easy way to differentiate objects if each + // objects is served by a separate servant. +}; diff --git a/TAO/orbsvcs/tests/FT_Naming/Federation/Federation.mpc b/TAO/orbsvcs/tests/FT_Naming/Federation/Federation.mpc new file mode 100644 index 00000000000..eeab5127922 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Federation/Federation.mpc @@ -0,0 +1,38 @@ +// -*- MPC -*- +// $Id$ + +project(*idl): taoidldefaults { + IDL_Files { + Test.idl + } + custom_only = 1 +} + +project(*Client): namingexe { + exename = client + after += *idl + Source_Files { + client.cpp + } + Source_Files { + TestC.cpp + } + IDL_Files { + } +} + +project(*Server): namingexe, portableserver { + exename = server + after += *idl + Source_Files { + server.cpp + Hello.cpp + } + Source_Files { + TestC.cpp + TestS.cpp + } + IDL_Files { + } +} + diff --git a/TAO/orbsvcs/tests/FT_Naming/Federation/Hello.cpp b/TAO/orbsvcs/tests/FT_Naming/Federation/Hello.cpp new file mode 100644 index 00000000000..817955f5d36 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Federation/Hello.cpp @@ -0,0 +1,23 @@ +// +// $Id$ +// +#include "Hello.h" + + + +Hello::Hello (CORBA::ORB_ptr orb) + : orb_ (CORBA::ORB::_duplicate (orb)) +{ +} + +char * +Hello::get_string (void) +{ + return CORBA::string_dup ( ACE_TEXT ("Hello there!")); +} + +void +Hello::shutdown (void) +{ + this->orb_->shutdown (0); +} diff --git a/TAO/orbsvcs/tests/FT_Naming/Federation/Hello.h b/TAO/orbsvcs/tests/FT_Naming/Federation/Hello.h new file mode 100644 index 00000000000..3a840d3d88d --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Federation/Hello.h @@ -0,0 +1,31 @@ +// +// $Id$ +// + +#ifndef HELLO_H +#define HELLO_H +#include /**/ "ace/pre.h" + +#include "TestS.h" + +/// Implement the Test::Hello interface +class Hello + : public virtual POA_Test::Hello +{ +public: + /// Constructor + Hello (CORBA::ORB_ptr orb); + + // = The skeleton methods + virtual char * get_string (void); + + virtual void shutdown (void); + +private: + /// Use an ORB reference to convert strings to objects and shutdown + /// the application. + CORBA::ORB_var orb_; +}; + +#include /**/ "ace/post.h" +#endif /* HELLO_H */ diff --git a/TAO/orbsvcs/tests/FT_Naming/Federation/README b/TAO/orbsvcs/tests/FT_Naming/Federation/README new file mode 100644 index 00000000000..b2d7e2838f4 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Federation/README @@ -0,0 +1,70 @@ +$Id$ + +This tests the federated fault tolerant naming service use case: + +To run all tests automatically - + execute Perl script run_test.pl + +Example Perl script execution output: +$./run_test.pl +Hello object bound in Naming Service B +Root context of NS B bound in Naming Service A under name 'nsB' +Wrote IOR file +Starting client +**** Narrowed root NamingContext +**** Resolved #nsB/example/Hello +(12960|3069859584) - string returned <Hello there!> +INFO: server being killed. +INFO: removing <NameService1> +INFO: removing <NameService2> +$ + +To run tests manually - + start the 2 redundant pairs of tao_ft_naming (see + TAO/orbsvcs/Naming_Service/README for valid options), + then run ./server and ./client as shown below: + +NOTE: if running tests manually, the NameService1 and NameService2 directories +must exist before starting the Naming Service and these directories must be +cleaned out manually after stopping the Naming Service. + +1) server connects to Naming Service B (localhost:9932) and attempts to bind + context "example" to it. + +2) server attempts to bind "Hello" object to the newly created context "example". + +3) server connects to Naming Service A (localhost:9931) and bind + Naming Service B as name "nsB". + +4) server writes out ior file. + +5) client connects to Naming Service A (localhost:9931) and attempts to resolve + "nsB/example/Hello" from the root context. + +6) client attempts to narrow the Hello object and reports the output of the + Hello object's get_string() method. + +Example (on a Unix system): + +$tao_ft_naming --primary -ORBListenEndPoints iiop://localhost:9931 \ + -r NameService1 & +$tao_ft_naming --backup -ORBListenEndPoints iiop://localhost:9933 -c ns1.ior \ + -g nm1.ior -r NameService1 & + +$tao_ft_naming --primary -ORBListenEndPoints iiop://localhost:9932 \ + -r NameService2 & +$tao_ft_naming --backup -ORBListenEndPoints iiop://localhost:9934 -c ns2.ior \ + -g nm2.ior -r NameService2 & + +$./server -o test.ior & + +Hello object bound in Naming Service B +Root context of NS B bound in Naming Service A under name 'nsB' +Wrote IOR file + +$./client + +**** Narrowed root NamingContext +**** Resolved #nsB/example/Hello +(10911|3069798144) - string returned <Hello there!> + diff --git a/TAO/orbsvcs/tests/FT_Naming/Federation/Test.idl b/TAO/orbsvcs/tests/FT_Naming/Federation/Test.idl new file mode 100644 index 00000000000..98ed1b2e3a3 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Federation/Test.idl @@ -0,0 +1,26 @@ +// +// $Id$ +// + +/// Put the interfaces in a module, to avoid global namespace pollution +module Test +{ + /// A very simple interface + interface Hello + { + /// Return a simple string + string get_string (); + + /// A method to shutdown the ORB + /** + * This method is used to simplify the test shutdown process + */ + oneway void shutdown (); + }; + + /// A very simple interface + interface NsShutdown + { + oneway void shutdown (); + }; +}; diff --git a/TAO/orbsvcs/tests/FT_Naming/Federation/client.cpp b/TAO/orbsvcs/tests/FT_Naming/Federation/client.cpp new file mode 100644 index 00000000000..0fa3468806d --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Federation/client.cpp @@ -0,0 +1,78 @@ +// $Id$ + +#include "TestC.h" +#include "orbsvcs/CosNamingC.h" +#include "ace/Get_Opt.h" + + +int +ACE_TMAIN(int argc, ACE_TCHAR *argv[]) +{ + try + { + CORBA::ORB_var orb = CORBA::ORB_init (argc, argv); + + CORBA::Object_var tmp = + orb->string_to_object ( + ACE_TEXT_ALWAYS_CHAR ("corbaloc:iiop:1.2@localhost:9931/NameService")); + + CosNaming::NamingContext_var root = + CosNaming::NamingContext::_narrow (tmp.in ()); + + if (CORBA::is_nil (root.in ())) + { + ACE_ERROR_RETURN ((LM_DEBUG, + ACE_TEXT ("Nil NamingService reference\n")), + 1); + } + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("**** Narrowed root NamingContext\n"))); + + CosNaming::Name name; + name.length(3); + name[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("nsB")); + name[1].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("example")); + name[2].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("Hello")); + + try + { + tmp = root->resolve (name); + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("**** Resolved #nsB/example/Hello\n"))); + + Test::Hello_var hello = + Test::Hello::_narrow (tmp.in ()); + + if (CORBA::is_nil (hello.in ())) + { + ACE_ERROR_RETURN ((LM_DEBUG, + ACE_TEXT ("Nil Test::Hello reference\n")), + 1); + } + + CORBA::String_var the_string = hello->get_string (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - string returned <%C>\n"), + the_string.in ())); + + hello->shutdown (); + } + catch (const CosNaming::NamingContext::CannotProceed&) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Caught correct exception\n"))); + } + + orb->shutdown (); + orb->destroy (); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("Exception caught:")); + return 1; + } + + return 0; +} diff --git a/TAO/orbsvcs/tests/FT_Naming/Federation/run_test.pl b/TAO/orbsvcs/tests/FT_Naming/Federation/run_test.pl new file mode 100755 index 00000000000..b67cb26aa9a --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Federation/run_test.pl @@ -0,0 +1,268 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# This is a Perl script that runs a Naming Service test. It starts +# all the servers and clients as necessary. +# -*- perl -*- + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::TestTarget; +use Cwd; + +#$ENV{ACE_TEST_VERBOSE} = "1"; + +$status = 0; +$debug_level = '0'; +$quiet = 0; + +if ($ARGV[0] eq '-q') { + $quiet = 1; +} + +foreach $i (@ARGV) { + if ($i eq '-debug') { + $debug_level = '10'; + } +} + +sub clean_persistence_dir($$) +{ + my $target = shift; + my $directory_name = shift; + + chdir $directory_name; + opendir(THISDIR, "."); + @allfiles = grep(!/^\.\.?$/, readdir(THISDIR)); + closedir(THISDIR); + foreach $tmp (@allfiles){ + $target->DeleteFile ($tmp); + } + chdir ".."; +} + +# Make sure that the directory to use to hold the naming contexts exists +# and is cleaned out +sub init_naming_context_directory($$) +{ + my $target = shift; + my $directory_name = shift; + + if ( ! -d $directory_name ) { + mkdir ($directory_name, 0777); + } else { + clean_persistence_dir ($target, $directory_name); + } +} + + +# Variables for command-line arguments to client and server +# executables. +my $ns_orb_primary_port1 = 9931; +my $ns_orb_primary_port2 = 9932; +my $ns_orb_backup_port1 = 9933; +my $ns_orb_backup_port2 = 9934; + +my $ns_primary_endpoint1 = "iiop://localhost:$ns_orb_primary_port1"; +my $ns_backup_endpoint1 = "iiop://localhost:$ns_orb_backup_port1"; +my $ns_primary_endpoint2 = "iiop://localhost:$ns_orb_primary_port2"; +my $ns_backup_endpoint2 = "iiop://localhost:$ns_orb_backup_port2"; + +my $ns1_ior = "ns1.ior"; +my $ns2_ior = "ns2.ior"; +my $nm1_ior = "nm1.ior"; +my $nm2_ior = "nm2.ior"; +my $iorbase = "test.ior"; + +my $ns1 = PerlACE::TestTarget::create_target (1) || die "Create target 1 failed\n"; +my $ns2 = PerlACE::TestTarget::create_target (2) || die "Create target 2 failed\n"; +my $server = PerlACE::TestTarget::create_target (3) || die "Create target 3 failed\n"; +my $client = PerlACE::TestTarget::create_target (4) || die "Create target 4 failed\n"; + +my $server_iorfile = $server->LocalFile ($iorbase); +my $ns1_iorfile = $ns1->LocalFile ($ns1_ior); +my $ns2_iorfile = $ns2->LocalFile ($ns2_ior); +my $nm1_iorfile = $ns1->LocalFile ($nm1_ior); +my $nm2_iorfile = $ns2->LocalFile ($nm2_ior); + +$server->DeleteFile ($iorbase); +$ns1->DeleteFile ($ns1_ior); +$ns2->DeleteFile ($ns2_ior); + +$SV = $server->CreateProcess ("server", "-ORBdebuglevel $debug_level -o $server_iorfile"); +$CL = $client->CreateProcess ("client", "-ORBdebuglevel $debug_level"); + +my $tao_ft_naming = "$ENV{TAO_ROOT}/orbsvcs/Naming_Service/tao_ft_naming"; + +my $name_dir1 = "NameService1"; +my $name_dir2 = "NameService2"; + +init_naming_context_directory ($ns1, $name_dir1); +init_naming_context_directory ($ns2, $name_dir2); + +my $ns1_primary_args = "--primary -ORBListenEndPoints $ns_primary_endpoint1 ". + "-r $name_dir1"; + +my $ns1_backup_args = "--backup -ORBListenEndPoints $ns_backup_endpoint1 ". + "-c $ns1_iorfile -g $nm1_iorfile ". + "-r $name_dir1"; + +my $ns2_primary_args = "--primary -ORBListenEndPoints $ns_primary_endpoint2 ". + "-r $name_dir2"; + +my $ns2_backup_args = "--backup -ORBListenEndPoints $ns_backup_endpoint2 ". + "-c $ns2_iorfile -g $nm2_iorfile ". + "-r $name_dir2"; + +$NS1_PRIMARY = $ns1->CreateProcess($tao_ft_naming, $ns1_primary_args ); +$NS1_BACKUP = $ns1->CreateProcess($tao_ft_naming, $ns1_backup_args ); + +$NS2_PRIMARY = $ns2->CreateProcess($tao_ft_naming, $ns2_primary_args ); +$NS2_BACKUP = $ns2->CreateProcess($tao_ft_naming, $ns2_backup_args ); + +my $replica_primary_ior = "ns_replica_primary.ior"; +my $ns1_replica_primary_ior = "$name_dir1/$replica_primary_ior"; +my $ns2_replica_primary_ior = "$name_dir2/$replica_primary_ior"; + +################################################################################ +# setup END block to cleanup after exit call +################################################################################ +END +{ + $server->DeleteFile ($iorbase); + + $ns1->DeleteFile ($ns1_ior); + $ns1->DeleteFile ($nm1_ior); + + $ns2->DeleteFile ($ns2_ior); + $ns2->DeleteFile ($nm2_ior); + + if ( -d $name_dir1 ) { + print STDERR "INFO: removing <$name_dir1>\n"; + clean_persistence_dir ($ns1, $name_dir1); + rmdir $name_dir1; + } + + if ( -d $name_dir2 ) { + print STDERR "INFO: removing <$name_dir2>\n"; + clean_persistence_dir ($ns2, $name_dir2); + rmdir $name_dir2; + } +} + +# Run two Naming Servers +$process_status = $NS1_PRIMARY->Spawn (); + +if ($process_status != 0) { + print STDERR "ERROR: ns1 returned $process_status\n"; + exit 1; +} + +if ($ns1->WaitForFileTimed ($ns1_replica_primary_ior, + $ns1->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$name_dir1/ns_replica_primary.ior>\n"; + $NS1_PRIMARY->Kill (); $NS1_PRIMARY->TimedWait (1); + exit 1; +} + +$process_status = $NS1_BACKUP->Spawn (); + +if ($process_status != 0) { + print STDERR "ERROR: ns1 returned $process_status\n"; + exit 1; +} + +if ($ns1->WaitForFileTimed ($ns1_ior, + $ns1->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$ns1_ior>\n"; + $NS1_BACKUP->Kill (); $NS1_BACKUP->TimedWait (1); + $NS1_PRIMARY->Kill (); $NS1_PRIMARY->TimedWait (1); + exit 1; +} + +$process_status = $NS2_PRIMARY->Spawn (); + +if ($process_status != 0) { + print STDERR "ERROR: ns2 returned $process_status\n"; + $NS1_BACKUP->Kill (); $NS1_BACKUP->TimedWait (1); + $NS1_PRIMARY->Kill (); $NS1_PRIMARY->TimedWait (1); + exit 1; +} + +if ($ns2->WaitForFileTimed ($ns2_replica_primary_ior, + $ns2->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$name_dir2/ns_replica_primary.ior>\n"; + $NS1_BACKUP->Kill (); $NS1_BACKUP->TimedWait (1); + $NS1_PRIMARY->Kill (); $NS1_PRIMARY->TimedWait (1); + exit 1; +} + +$process_status = $NS2_BACKUP->Spawn (); +if ($process_status != 0) { + print STDERR "ERROR: ns2 returned $process_status\n"; + $NS2_PRIMARY->Kill (); $NS2_PRIMARY->TimedWait (1); + $NS1_BACKUP->Kill (); $NS1_BACKUP->TimedWait (1); + $NS1_PRIMARY->Kill (); $NS1_PRIMARY->TimedWait (1); + exit 1; +} + +if ($ns2->WaitForFileTimed ($ns2_ior, + $ns2->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$ns2_iorfile>\n"; + $NS2_BACKUP->Kill (); $NS2_BACKUP->TimedWait (1); + $NS2_PRIMARY->Kill (); $NS2_PRIMARY->TimedWait (1); + $NS1_BACKUP->Kill (); $NS1_BACKUP->TimedWait (1); + $NS1_PRIMARY->Kill (); $NS1_PRIMARY->TimedWait (1); + exit 1; +} + +$process_status = $SV->Spawn (); + +if ($process_status != 0) { + print STDERR "ERROR: server returned $process_status\n"; + $NS2_BACKUP->Kill (); $NS2_BACKUP->TimedWait (1); + $NS2_PRIMARY->Kill (); $NS2_PRIMARY->TimedWait (1); + $NS1_BACKUP->Kill (); $NS1_BACKUP->TimedWait (1); + $NS1_PRIMARY->Kill (); $NS1_PRIMARY->TimedWait (1); + exit 1; +} + +if ($server->WaitForFileTimed ($iorbase, + $server->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$server_iorfile>\n"; + $NS2_BACKUP->Kill (); $NS2_BACKUP->TimedWait (1); + $NS2_PRIMARY->Kill (); $NS2_PRIMARY->TimedWait (1); + $NS1_BACKUP->Kill (); $NS1_BACKUP->TimedWait (1); + $NS1_PRIMARY->Kill (); $NS1_PRIMARY->TimedWait (1); + $SV->Kill (); $SV->TimedWait (1); + exit 1; +} + +print STDERR "Starting client\n"; +$process_status = $CL->SpawnWaitKill (15); + +if ($process_status != 0) { + print STDERR "ERROR: client returned $process_status\n"; + $status = 1; +} + +$process_status = $SV->TerminateWaitKill ($server->ProcessStopWaitInterval()); +if ($process_status != 0) { + print STDERR "ERROR: server returned $process_status\n"; + $status = 1; +} + +$process_status = $CL->TerminateWaitKill ($client->ProcessStopWaitInterval()); + +if ($process_status != 0) { + print STDERR "ERROR: client returned $process_status\n"; + $status = 1; +} + +$NS2_BACKUP->Kill (); $NS2_BACKUP->TimedWait (1); +$NS2_PRIMARY->Kill (); $NS2_PRIMARY->TimedWait (1); +$NS1_BACKUP->Kill (); $NS1_BACKUP->TimedWait (1); +$NS1_PRIMARY->Kill (); $NS1_PRIMARY->TimedWait (1); + +exit $status; diff --git a/TAO/orbsvcs/tests/FT_Naming/Federation/server.cpp b/TAO/orbsvcs/tests/FT_Naming/Federation/server.cpp new file mode 100644 index 00000000000..a1bee3a289b --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Federation/server.cpp @@ -0,0 +1,176 @@ +// $Id$ + +#include "Hello.h" +#include "orbsvcs/CosNamingC.h" +#include "ace/Get_Opt.h" +#include "ace/Task.h" + +const ACE_TCHAR *ior_output_file = ACE_TEXT ("test.ior"); + +class TestTask : public ACE_Task_Base +{ +public: + TestTask (int argc, ACE_TCHAR **argv); + virtual int svc (); + + int parse_args (int argc, ACE_TCHAR **argv); + + void end(); +private: + CORBA::ORB_var orb_; + CORBA::Boolean shutdown_ns_; +}; + +TestTask::TestTask(int argc, ACE_TCHAR **argv) +{ + orb_ = CORBA::ORB_init (argc, argv, ACE_TEXT_ALWAYS_CHAR ("ServerORB")); + shutdown_ns_ = false; + parse_args (argc, argv); +} + +void TestTask::end() +{ + orb_->shutdown(0); + this->wait(); +} + +int +TestTask::parse_args (int argc, ACE_TCHAR **argv) +{ + ACE_Get_Opt get_opts (argc, argv, ACE_TEXT ("o:s")); + int c; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 's': + shutdown_ns_ = true; + break; + case 'o': + ior_output_file = get_opts.opt_arg (); + break; + } + // Indicates successful parsing of the command line + return 0; +} + +int TestTask::svc() +{ + + try { + // Get reference to Root POA + CORBA::Object_var obj = orb_->resolve_initial_references ( + ACE_TEXT_ALWAYS_CHAR ("RootPOA")); + + PortableServer::POA_var poa = PortableServer::POA::_narrow (obj.in ()); + + // Activate POA Manager + PortableServer::POAManager_var mgr = poa->the_POAManager (); + mgr->activate (); + + // Find the Naming Service + obj = orb_->string_to_object ( + ACE_TEXT_ALWAYS_CHAR ("corbaloc:iiop:1.2@localhost:9932/NameService")); + + CosNaming::NamingContext_var rootB = + CosNaming::NamingContext::_narrow (obj.in ()); + + if (CORBA::is_nil (rootB.in ())) { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Error, Nil Naming Context reference\n"))); + return 1; + } + // Bind the example Naming Context, if necessary + CosNaming::NamingContext_var example_nc; + CosNaming::Name name; + name.length(1); + name[0].id = CORBA::string_dup( ACE_TEXT_ALWAYS_CHAR ("example")); + try + { + obj = rootB->resolve (name); + example_nc = + CosNaming::NamingContext::_narrow (obj.in ()); + } + catch (const CosNaming::NamingContext::NotFound&) + { + example_nc = rootB->bind_new_context (name); + } + + // Bind the Test object + name.length (2); + name[1].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("Hello")); + + // Create an object + Hello servant (orb_.in ()); + PortableServer::ObjectId_var oid = poa->activate_object (&servant); + obj = poa->id_to_reference (oid.in ()); + rootB->rebind (name, obj.in ()); + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Hello object bound in Naming Service B\n"))); + + name.length (1); + name[0].id = CORBA::string_dup (ACE_TEXT_ALWAYS_CHAR ("nsB")); + + obj = orb_->string_to_object ( + ACE_TEXT_ALWAYS_CHAR ("corbaloc:iiop:1.2@localhost:9931/NameService")); + + CosNaming::NamingContext_var rootA = + CosNaming::NamingContext::_narrow (obj.in ()); + + rootA->bind_context (name, rootB.in ()); + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Root context of NS B bound in Naming Service A ") + ACE_TEXT ("under name 'nsB'\n"))); + + CORBA::String_var ior = + orb_->object_to_string (obj.in ()); + + // Output the IOR to the <ior_output_file> + FILE *output_file= ACE_OS::fopen (ior_output_file, "w"); + if (output_file == 0) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Cannot open output file %s for writing ") + ACE_TEXT ("IOR: %C\n"), + ior_output_file, + ior.in ()), + 1); + ACE_OS::fprintf (output_file, ACE_TEXT ("%s"), ior.in ()); + ACE_OS::fclose (output_file); + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Wrote IOR file\n"))); + + // Normally we run the orb and the orb is shutdown by + // calling TestTask::end(). + // Accept requests + orb_->run(); + orb_->destroy(); + + return 0; + } + catch (CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("CORBA exception: ")); + } + + return -1; +} + +int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // Start the Test task + TestTask test_ (argc, argv); + if (test_.activate() == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Unable to start test task.\n")), + -1); + } + + // Wait the tasks to finish. + test_.thr_mgr ()->wait(); + + return 0; +} diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/Basic.cpp b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/Basic.cpp new file mode 100644 index 00000000000..f39b658f78e --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/Basic.cpp @@ -0,0 +1,61 @@ +// $Id$ + +#include "Basic.h" +#include "LB_server.h" +#include "orbsvcs/PortableGroup/PG_Property_Set.h" + +Basic::Basic (CORBA::Object_ptr object_group, + FT_Naming::NamingManager_ptr lm, + CORBA::ORB_ptr orb, + const char *loc) + : object_group_name_ ("Basic Group"), orb_ (CORBA::ORB::_duplicate (orb)) +{ + this->object_group_ = CORBA::Object::_duplicate (object_group); + this->nm_ = FT_Naming::NamingManager::_duplicate (lm); + this->location_ = CORBA::string_dup (loc); +} + +char * +Basic::get_string (void) +{ + return CORBA::string_dup (this->location_.in ()); +} + +void +Basic::remove_member (void) +{ + try + { + PortableGroup::Location location (1); + location.length (1); + location[0].id = CORBA::string_dup (this->location_.in ()); + this->nm_->remove_member (this->object_group_.in (), + location); + + ACE_DEBUG ((LM_DEBUG, "(%P|%t) - Removed Member at Location <%s>\n", + this->location_.in ())); + + } + catch (const PortableGroup::ObjectNotFound& ex) + { + ex._tao_print_exception ("Caught exception in remove_member"); + throw CORBA::INTERNAL (); + } + catch (const PortableGroup::MemberNotFound& ex) + { + ex._tao_print_exception ("Caught exception in remove_member"); + throw CORBA::INTERNAL (); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ("Exception caught while destroying member\n"); + } + +} + + +void +Basic::shutdown (void) +{ + this->orb_->shutdown (0); +} diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/Basic.h b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/Basic.h new file mode 100644 index 00000000000..37aec36f681 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/Basic.h @@ -0,0 +1,59 @@ +// -*- C++ -*- +// +// $Id$ + +#ifndef BASIC_H +#define BASIC_H + +#include "TestS.h" +#include "orbsvcs/FT_NamingManagerC.h" +#include "orbsvcs/PortableGroupC.h" + +#if defined (_MSC_VER) +# pragma warning(push) +# pragma warning (disable:4250) +#endif /* _MSC_VER */ + +class LB_Basic_Test; + +/// Implement the Test::Basic interface +class Basic + : public virtual POA_Test::Basic +{ +public: + /// Constructor + Basic (CORBA::Object_ptr object_group, + FT_Naming::NamingManager_ptr lm, + CORBA::ORB_ptr orb, + const char *loc); + + virtual char * get_string (void); + + virtual void shutdown (void); + + virtual void remove_member (void); + +private: + + const char* object_group_name_; + + /// Use an ORB reference to convert strings to objects and shutdown + /// the application. + CORBA::ORB_var orb_; + + /// Load Manager Reference used to delete the servant reference from the + /// object group. + FT_Naming::NamingManager_var nm_; + + /// location of the servant + CORBA::String_var location_; + + /// Object Group reference. + CORBA::Object_var object_group_; +}; + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif /* _MSC_VER */ + +#endif /* BASIC_H */ diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/LB_server.cpp b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/LB_server.cpp new file mode 100644 index 00000000000..3bcff5045b7 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/LB_server.cpp @@ -0,0 +1,222 @@ +// $Id$ + +#include "LB_server.h" +#include "Basic.h" + +#include "TestC.h" +#include "ace/OS_NS_stdio.h" + +LB_server::LB_server (int argc, ACE_TCHAR **argv) + : argc_ (argc) + , argv_ (argv) + , ior_output_file_(ACE_TEXT("obj.ior")) +{ +} + +int +LB_server::destroy (void) +{ + try + { + this->naming_manager_->delete_object_group ("Basic Group"); + this->orb_->destroy (); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Exception caught while destroying LB_server\n")); + return -1; + } + return 0; + +} + +CORBA::ORB_ptr +LB_server::orb (void) +{ + return this->orb_.in (); +} + +CORBA::Object_ptr +LB_server::object_group (void) +{ + return this->object_group_.in (); +} + +FT_Naming::NamingManager_ptr +LB_server::naming_manager (void) +{ + return this->naming_manager_.in (); +} + +int +LB_server::write_ior_to_file (const char *ior) +{ + FILE *output_file = + ACE_OS::fopen (this->ior_output_file_, "w"); + + if (output_file == 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Cannot open output file for writing IOR:"))); + return -1; + } + + ACE_OS::fprintf (output_file, "%s", ior); + ACE_OS::fclose (output_file); + return 0; +} + +int +LB_server::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("o:")); + int c; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'o': + this->ior_output_file_ = get_opts.opt_arg (); + break; + case '?': + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("usage: %s ") + ACE_TEXT ("-o <iorfile>") + ACE_TEXT ("\n"), + argv [0]), + -1); + } + // Indicates successful parsing of the command line + return 0; +} + +int +LB_server::start_orb_and_poa (void) +{ + try + { + // Initialise the ORB. + this->orb_ = CORBA::ORB_init (this->argc_, this->argv_); + + CORBA::Object_var poa_object = + this->orb_->resolve_initial_references("RootPOA"); + + if (CORBA::is_nil (poa_object.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT (" (%P|%t) Unable to initialize the POA.\n")), + -1); + + this->root_poa_ = PortableServer::POA::_narrow (poa_object.in ()); + + PortableServer::POAManager_var poa_manager = + this->root_poa_->the_POAManager (); + + poa_manager->activate (); + + ACE_Time_Value timeout (10); // Wait up to 10 seconds for the naming service + if (name_svc_.init (this->orb_, &timeout) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + ACE_TEXT ("LB_server: Could not connect to naming ") + ACE_TEXT ("service.\n")), + -1); + + CORBA::Object_var obj = + this->orb_->resolve_initial_references ("NamingManager"); + + this->naming_manager_ = + FT_Naming::NamingManager::_narrow (obj.in ()); + + if (CORBA::is_nil (this->naming_manager_.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT (" (%P|%t) Unable to get Naming ") + ACE_TEXT ("Manager Reference\n")), + -1); + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Exception raised initialising ORB or POA")); + return -1; + } + + return 0; + +} + +int +LB_server::create_object_group (void) +{ + try + { + if (this->parse_args (argc_, argv_) != 0) + return -1; + + PortableGroup::Criteria criteria (2); + criteria.length (1); + + PortableGroup::Property &mem_style = criteria[0]; + mem_style.nam.length (1); + + // Set the membership style property + mem_style.nam[0].id = + CORBA::string_dup (ACE_TEXT ("org.omg.PortableGroup.MembershipStyle")); + PortableGroup::MembershipStyleValue msv = + PortableGroup::MEMB_APP_CTRL; + mem_style.val <<= msv; + + this->object_group_ = this->naming_manager_->create_object_group ( + ACE_TEXT ("Basic Group"), + FT_Naming::ROUND_ROBIN, + criteria); + + CORBA::String_var ior = + this->orb_->object_to_string (this->object_group_.in ()); + + this->write_ior_to_file (ior.in ()); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Exception raised while creating object group")); + return -1; + } + + return 0; + +} + +int +LB_server::register_servant (Basic *servant, const char *loc) +{ + try + { + Test::Basic_var basic = + servant->_this (); + + PortableGroup::Location location (1); + location.length (1); + + location[0].id = CORBA::string_dup (loc); + + this->naming_manager_->add_member (this->object_group_.in (), + location, + basic.in ()); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Exception raised while registering servant")); + return -1; + } + + return 0; +} + +TAO_Naming_Client& +LB_server::name_svc () +{ + return name_svc_; +} diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/LB_server.h b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/LB_server.h new file mode 100644 index 00000000000..d6df78c52f8 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/LB_server.h @@ -0,0 +1,98 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file LB_server.h + * + * $Id$ + * + * @author Jaiganesh Balasubramanian <jai@doc.ece.uci.edu> + * @author Ossama Othman <ossama@uci.edu> + */ +//============================================================================= + + +#include "orbsvcs/FT_NamingManagerC.h" +#include "orbsvcs/PortableGroupC.h" +#include "tao/PortableServer/PortableServer.h" +#include "ace/Get_Opt.h" +#include "orbsvcs/Naming/Naming_Client.h" + +// Forward Declaration of the kind of servant we would like to handle +// by the server. +class Basic; + +/** + * @class LB_server + * + * @brief Encapsulate the test in class. + * + * TODO: Fix description + * This is a class used to retrieve the NamingManager reference and + * create the Object Group. Servants add themselves to the object + * group and the object group reference is published to the clients. + * Clients then invoke the "servant operations" on the NamingManager + * itself. At this point the Load Balancing cycle starts. + */ +class LB_server +{ +public: + + /// Constructor + LB_server (int argc, ACE_TCHAR **argv); + + /// destroys NamingManager, ORB and POA. + int destroy (void); + + /// start the ORB. + int start_orb_and_poa (void); + + /// Get the NamingManager Interface. + int init (int argc, ACE_TCHAR **argv); + + /// Create the Object Group using the Load Manager Reference. + int create_object_group (void); + + /// register the servants with the object group. + int register_servant (Basic *servant, const char *loc); + + /// obtain the name service facade + TAO_Naming_Client& name_svc (); + + /// for servants to register to the initialised ORB. + CORBA::ORB_ptr orb (void); + + /// for servants to get the reference for object_group. + CORBA::Object_ptr object_group (void); + + /// for servants to get the reference for object_group. + FT_Naming::NamingManager_ptr naming_manager (void); + +private: + + int parse_args (int, ACE_TCHAR **); + +private: + + /// Load Manager + FT_Naming::NamingManager_var naming_manager_; + + /// Object Group. + CORBA::Object_var object_group_; + + /// factory id for the object group. + PortableGroup::GenericFactory::FactoryCreationId_var fcid_; + + /// Used to force the creation of the object group only once. + static int called_once_; + + /// write the IOR to a file so that it can be read later. + int write_ior_to_file (const char *); + + CORBA::ORB_var orb_; + int argc_; + ACE_TCHAR **argv_; + PortableServer::POA_var root_poa_; + const ACE_TCHAR *ior_output_file_; + TAO_Naming_Client name_svc_; +}; diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/Load_Balancing_Name_Service.mpc b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/Load_Balancing_Name_Service.mpc new file mode 100644 index 00000000000..0c1338cb2fd --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/Load_Balancing_Name_Service.mpc @@ -0,0 +1,34 @@ +// -*- MPC -*- +// $Id$ + +project(*idl): taoidldefaults { + IDL_Files { + Test.idl + } + custom_only = 1 +} + +project(*server): ftnaming { + after += *idl + exename = server + Source_Files { + TestC.cpp + TestS.cpp + server.cpp + LB_server.cpp + Basic.cpp + } + IDL_Files { + } +} + +project(*client): ftnaming { + after += *idl + exename = client + Source_Files { + TestC.cpp + client.cpp + } + IDL_Files { + } +} diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/README b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/README new file mode 100644 index 00000000000..44197dfb409 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/README @@ -0,0 +1,8 @@ +$Id$ + +This program tests the application controlled membership support +of the FT_Naming_Service. The aim is to allow the application +to create object groups and add them to the naming service. When +the client resolves an object group from the naming service, the +load balancing strategy is applied. Currently the test only supports +the RoundRobin load balancing strategy. diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/Test.idl b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/Test.idl new file mode 100644 index 00000000000..21d10f6644c --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/Test.idl @@ -0,0 +1,27 @@ +// +// $Id$ + +#include "orbsvcs/FT_NamingManager.idl" + +/// Put the interfaces in a module, to avoid global namespace pollution +module Test +{ + typedef FT_Naming::LoadBalancingStrategyValue LoadBalancingStrategyValue; + + /// A very simple interface + interface Basic + { + /// Return a simple string + string get_string (); + + /// A method to shutdown the ORB + /** + * This method is used to simplify the test shutdown process + */ + oneway void shutdown (); + + /// A method to remove the servant from the NamingManager Object Group. + oneway void remove_member (); + }; +}; + diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/client.cpp b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/client.cpp new file mode 100644 index 00000000000..17a8b7ad7d6 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/client.cpp @@ -0,0 +1,160 @@ +// $Id$ + +#include "TestC.h" +#include "ace/Get_Opt.h" +#include "orbsvcs/Naming/Naming_Client.h" +#include "ace/Time_Value.h" + +const ACE_TCHAR *ior = ACE_TEXT("file://obj.ior"); + +int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("k:")); + int c; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'k': + ior = get_opts.opt_arg (); + break; + + case '?': + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("usage: %s ") + ACE_TEXT ("-k <ior> ") + ACE_TEXT ("\n"), + argv [0]), + -1); + } + // Indicates successful parsing of the command line + return 0; +} + +int +ACE_TMAIN(int argc, ACE_TCHAR *argv[]) +{ + try + { + CORBA::ORB_var orb = + CORBA::ORB_init (argc, argv); + + if (parse_args (argc, argv) != 0) + return 1; + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - Acquiring Name Service\n"))); + + TAO_Naming_Client name_svc; + try { + + ACE_Time_Value timeout (10); // Wait up to 10 seconds for the naming service + if (name_svc.init (orb.in (), &timeout) != 0) + ACE_ERROR_RETURN ((LM_DEBUG, + ACE_TEXT ("client: Could not connect to ") + ACE_TEXT ("naming service.\n")), + 1); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Exception caught while initializing name ") + ACE_TEXT ("service facade:")); + return 1; + } + + CosNaming::Name name (1); + name.length (1); + name[0].id = CORBA::string_dup ("basic_name"); + + CORBA::Object_var tmp; + Test::Basic_var basic; + + // Iterate enough so we get a few wraparrounds + for (int i = 0; i < 15; i++) + { + try { + + // Each time we invoke resolve, we get a different member + tmp = + name_svc->resolve (name); + + // Narrow it to a Basic object + basic = + Test::Basic::_narrow (tmp.in ()); + + } + catch (CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("Error resolving name.\n")); + } + + if (CORBA::is_nil (basic.in ())) + { + ACE_ERROR_RETURN ((LM_DEBUG, + ACE_TEXT ("Server obj ref not obtained ") + ACE_TEXT ("from Load Balancing Name Service\n"), + ior), + 1); + } + + try { + CORBA::String_var the_string = + basic->get_string (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - Client request handled ") + ACE_TEXT ("by object at <%s>\n"), + the_string.in ())); + + } + catch (CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Error invoking get_string on Basic object.\n")); + return 1; + } + + // Remove one member after we wrapped around to make sure naming manager can + // handle it successufully + if (i == 7) + { + try { + // Try removing a member + basic->remove_member (); + } + catch (CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Error invoking get_string on Basic object.\n")); + return 1; + } + } + } + + try { + + basic->shutdown (); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - Shutting down server\n"))); + } + catch (CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Error invoking get_string on Basic object.\n")); + return 1; + } + orb->destroy (); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Exception caught in client.cpp:")); + return 1; + } + + return 0; +} diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/run_test.pl b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/run_test.pl new file mode 100755 index 00000000000..729d20d38aa --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/run_test.pl @@ -0,0 +1,229 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +# This is a Perl script that runs a Naming Service test. It starts +# all the servers and clients as necessary. + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::TestTarget; +use Cwd; + +$status = 0; +$debug_level = '0'; +$startdir = getcwd(); + +my $test = PerlACE::TestTarget::create_target (1) || die "Create target 1 failed\n"; +my $server2 = PerlACE::TestTarget::create_target (2) || die "Create target 2 failed\n"; +my $client = PerlACE::TestTarget::create_target (3) || die "Create target 3 failed\n"; + + +# Variables for command-line arguments to naming service executables. +$hostname = $test->HostName (); + +$ns_orb_port1 = 10001 + $test->RandomPort (); +$ns_orb_port2 = 10002 + $test->RandomPort (); +$ns_endpoint1 = "iiop://$hostname:$ns_orb_port1"; +$ns_endpoint2 = "iiop://$hostname:$ns_orb_port2"; + +$naming_persistence_dir = "NameService"; +$groups_persistence_dir = "Groups"; + +$primary_iorfile = "$naming_persistence_dir/ns_replica_primary.ior"; +$combined_ns_iorfile = "combined_ns.ior"; +$combined_nm_iorfile = "combined_nm.ior"; + +my $test_combined_ns_iorfile = $test->LocalFile ($combined_ns_iorfile); +my $test_combined_nm_iorfile = $test->LocalFile ($combined_nm_iorfile); +my $test_primary_iorfile = $test->LocalFile ($primary_iorfile); + +my $server_obj_group_iorfile = "obj.ior"; + +#Files used by the server2 +my $server2_nm_iorfile = $server2->LocalFile ($combined_nm_iorfile); +$server2->DeleteFile($server2_nm_iorfile); +my $server2_ns_iorfile = $server2->LocalFile ($combined_ns_iorfile); +$server2->DeleteFile($server2_ns_iorfile); +my $server2_obj_group_iorfile = $server2->LocalFile ($server_obj_group_iorfile); +$server2->DeleteFile($server_obj_group_iorfile); + +#Files which used by client +my $client_ns_iorfile = $client->LocalFile ($combined_ns_iorfile); +$client->DeleteFile($client_ns_iorfile); + +$status = 0; + +print "INFO: Running the test in ", getcwd(), "\n"; + +sub clean_persistence_dir($$) +{ + my $target = shift; + my $directory_name = shift; + + chdir $directory_name; + opendir(THISDIR, "."); + @allfiles = grep(!/^\.\.?$/, readdir(THISDIR)); + closedir(THISDIR); + foreach $tmp (@allfiles){ + $target->DeleteFile ($tmp); + } + chdir ".."; +} + +# Make sure that the directory to use to hold the persistence data +# exists and is cleaned out. +sub init_persistence_directory($$) +{ + my $target = shift; + my $directory_name = shift; + + if ( ! -d $directory_name ) { + mkdir ($directory_name, 0777); + } else { + clean_persistence_dir ($target, $directory_name); + } +} + + +my $args = "-ORBEndPoint $ns_endpoint1 " . + "-m 0 " . + "-r $naming_persistence_dir " . + "-v $groups_persistence_dir " . + "--primary"; +my $prog = "$startdir/../../../Naming_Service/tao_ft_naming"; + +print STDERR "Starting Primary: $prog $args\n"; + +$NS1 = $test->CreateProcess ("$prog", "$args"); + +# Clean out the primary ior file to allow us to wait for it +$test->DeleteFile ($primary_iorfile); + +init_persistence_directory ($test, $naming_persistence_dir); +init_persistence_directory ($test, $groups_persistence_dir); + +$NS1->Spawn (); + +if ($test->WaitForFileTimed ($primary_iorfile, + $test->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$test_primary_iorfile>\n"; + $NS1->Kill (); $NS1->TimedWait (1); + exit 1; +} + +$args = "-ORBEndPoint $ns_endpoint2 " . + "-g $combined_nm_iorfile " . + "-c $combined_ns_iorfile " . + "-m 0 " . + "-r $naming_persistence_dir " . + "-v $groups_persistence_dir " . + "--backup"; + +$prog = "$startdir/../../../Naming_Service/tao_ft_naming"; + +print STDERR "Starting Backup: $prog $args\n"; + +$NS2 = $test->CreateProcess ("$prog", "$args"); + +# clean up the old generated ior files +$test->DeleteFile ($combined_ns_iorfile); +$test->DeleteFile ($combined_nm_iorfile); + +$NS2->Spawn (); + +if ($test->WaitForFileTimed ($combined_ns_iorfile, + $test->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$test_combined_ns_iorfile>\n"; + $NS2->Kill (); $NS2->TimedWait (1); + exit 1; +} + +$SV2 = $server2->CreateProcess ("server", + "-ORBdebuglevel $debug_level " . + "-ORBInitRef NameService=file://$server2_ns_iorfile " . + "-ORBInitRef NamingManager=file://$server2_nm_iorfile " . + "-o $server2_obj_group_iorfile"); + +$CL = $client->CreateProcess ("client", + "-ORBInitRef NameService=file://$client_ns_iorfile"); + +print STDERR "\n\n======== Running Application Controlled Membership Test================\n"; +print STDERR "\n"; + +print STDERR "This test uses the RoundRobin Load Balancing strategy \n"; + +print STDERR "6 servers are created and added into a Object Group\n"; + +print STDERR "When the client accesses an object group through the naming service, the"; +print STDERR "FT_Naming_Service will apply the RoundRobin load balancing strategy\n"; +print STDERR "selects one of the servers and then the client makes an invocations on\n"; +print STDERR "the server. This is done 15 times to ensure we support the wraparround\n"; +print STDERR "condition. When done, the application has to delete the object from the\n"; +print STDERR "object group. This is called the application controlled membership of\n"; +print STDERR "object group.\n"; +print STDERR "\n"; + +$server_status = $SV2->Spawn (); + +if ($server_status != 0) { + print STDERR "ERROR: server returned $server_status\n"; + exit 1; +} + +sub KillServers{ + $SV1->Kill (); $SV1->TimedWait (1); + $SV2->Kill (); $SV2->TimedWait (1); +} + +if ($server2->WaitForFileTimed ($server_obj_group_iorfile, + $server2->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$server2_obj_group_iorfile>\n"; + KillServers (); + exit 1; +} + +if ($server2->GetFile ($server_obj_group_iorfile) == -1) { + print STDERR "ERROR: cannot retrieve file <$server2_obj_group_iorfile>\n"; + KillServers (); + exit 1; +} + +if ($client->PutFile ($server_obj_group_iorfile) == -1) { + print STDERR "ERROR: cannot set file <$client_ns_iorfile>\n"; + KillServers (); + exit 1; +} + +$client_status = $CL->SpawnWaitKill ($client->ProcessStartWaitInterval() + 85); + +if ($client_status != 0) { + print STDERR "ERROR: client returned $client_status\n"; + $status = 1; +} + +$server_status = $SV2->WaitKill ($server2->ProcessStopWaitInterval()); + +if ($server_status != 0) { + print STDERR "ERROR: server returned $server_status\n"; + $status = 1; +} + +$server2->DeleteFile($nm_iorfile); +$server2->DeleteFile($server_obj_group_iorfile); +$client->DeleteFile($server_obj_group_iorfile); + +$NS1->Kill (); +$NS2->Kill (); + +$test->DeleteFile ($primary_iorfile); +$test->DeleteFile ($combined_ns_iorfile); + +clean_persistence_dir ($test, $naming_persistence_dir); +clean_persistence_dir ($test, $groups_persistence_dir); +rmdir ($naming_persistence_dir); +rmdir ($groups_persistence_dir); + +exit $status; diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/server.cpp b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/server.cpp new file mode 100644 index 00000000000..258cddbe1de --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/server.cpp @@ -0,0 +1,119 @@ +// $Id$ + +#include "LB_server.h" +#include "Basic.h" + +int +ACE_TMAIN(int argc, ACE_TCHAR *argv[]) +{ + try + { + const char *location1 = "MyLocation 1"; + const char *location2 = "MyLocation 2"; + const char *location3 = "MyLocation 3"; + const char *location4 = "MyLocation 4"; + const char *location5 = "MyLocation 5"; + const char *location6 = "MyLocation 6"; + + LB_server lb_server (argc, argv); + + if (lb_server.start_orb_and_poa () != 0) + return 1; + + if (lb_server.create_object_group () != 0) + return 1; + + CosNaming::Name name (1); + name.length (1); + name[0].id = CORBA::string_dup ("basic_name"); + try { + (lb_server.name_svc ())->rebind (name, lb_server.object_group ()); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ("Unable to bind object group in name service.\n"); + return 1; + } + + Basic *basic_servant1; + Basic *basic_servant2; + Basic *basic_servant3; + Basic *basic_servant4; + Basic *basic_servant5; + Basic *basic_servant6; + + ACE_NEW_RETURN (basic_servant1, + Basic (lb_server.object_group (), + lb_server.naming_manager (), + lb_server.orb (), + location1), + 1); + PortableServer::ServantBase_var owner_transfer1(basic_servant1); + + ACE_NEW_RETURN (basic_servant2, + Basic (lb_server.object_group (), + lb_server.naming_manager (), + lb_server.orb (), + location2), + 1); + PortableServer::ServantBase_var owner_transfer2(basic_servant2); + + ACE_NEW_RETURN (basic_servant3, + Basic (lb_server.object_group (), + lb_server.naming_manager (), + lb_server.orb (), + location3), + 1); + PortableServer::ServantBase_var owner_transfer3(basic_servant3); + + ACE_NEW_RETURN (basic_servant4, + Basic (lb_server.object_group (), + lb_server.naming_manager (), + lb_server.orb (), + location4), + 1); + PortableServer::ServantBase_var owner_transfer4(basic_servant4); + + ACE_NEW_RETURN (basic_servant5, + Basic (lb_server.object_group (), + lb_server.naming_manager (), + lb_server.orb (), + location5), + 1); + PortableServer::ServantBase_var owner_transfer5(basic_servant5); + + ACE_NEW_RETURN (basic_servant6, + Basic (lb_server.object_group (), + lb_server.naming_manager (), + lb_server.orb (), + location6), + 1); + PortableServer::ServantBase_var owner_transfer6(basic_servant6); + + if (lb_server.register_servant (basic_servant1, location1) == -1 + || lb_server.register_servant (basic_servant2, location2) == -1 + || lb_server.register_servant (basic_servant3, location3) == -1 + || lb_server.register_servant (basic_servant4, location4) == -1 + || lb_server.register_servant (basic_servant5, location5) == -1 + || lb_server.register_servant (basic_servant6, location6) == -1) + { + (void) lb_server.destroy (); + return 1; + } + + lb_server.orb ()->run (); + + ACE_DEBUG ((LM_DEBUG, "(%P|%t) server - event loop finished\n")); + + if (lb_server.destroy () == -1) + return 1; + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ("lb_server exception"); + return 1; + } + + return 0; +} diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/svc.conf b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/svc.conf new file mode 100644 index 00000000000..b6856698e51 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/svc.conf @@ -0,0 +1,3 @@ +# $Id$ + +static Resource_Factory "-ORBDropRepliesDuringShutdown 0" diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/windows.conf b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/windows.conf new file mode 100644 index 00000000000..e02d5089fce --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/windows.conf @@ -0,0 +1,3 @@ +# $Id$ + +dynamic Advanced_Resource_Factory Service_Object* TAO_Strategies:_make_TAO_Advanced_Resource_Factory () "-ORBReactorType select_mt" diff --git a/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/windows.conf.xml b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/windows.conf.xml new file mode 100644 index 00000000000..37af1733d3b --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Load_Balancing/windows.conf.xml @@ -0,0 +1,10 @@ +<?xml version='1.0'?> +<!-- Converted from windows.conf by svcconf-convert.pl --> +<ACE_Svc_Conf> + <!-- --> + <!-- $Id$ --> + <!-- --> + <dynamic id="Advanced_Resource_Factory" type="Service_Object"> + <initializer path="TAO_Strategies" init="_make_TAO_Advanced_Resource_Factory" params="-ORBReactorType select_mt"/> + </dynamic> +</ACE_Svc_Conf> diff --git a/TAO/orbsvcs/tests/FT_Naming/Replication/README b/TAO/orbsvcs/tests/FT_Naming/Replication/README new file mode 100644 index 00000000000..12cc280c87f --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Replication/README @@ -0,0 +1,54 @@ +$Id$ + +This application tests the replication features of TAO's FT Naming Service. + +To run all tests automatically - + execute Perl script run_test.pl + +To run tests manually - + start the Naming Service (see + TAO/orbsvcs/Naming_Service/README for valid options), + then run ./client the optional options are shown below. + +NOTE: if running tests manually, the NameService directory must exist +before starting the Naming Service and this directory must be cleaned out +manually after stopping the Naming Service. + +The following options exist: +--------------------------- +-b Breath of Context tree, default is 4, minimum is 2 + +-d Depth of Context tree, default is 4, minimum is 2 + +-o Breath of Object tree, default is 4, minimum is 2 + +-p ior for Naming Server 1 + +-q ior for Naming Server 2 + +The client creates two context trees, one of breath b and one of depth d, +and another node with o objects. It then removes the contexts b-1, d and +the object o-1. All these are done using the first name server. The +client then accesses contexts b, b-1, d, d-1, and objects o, o-1 looking +for the appropriate found/not-found returns using the second name server. + + Example (on a Unix system): + $ $TAO_ROOT/orbsvcs/Naming_Service/Naming_Service -o nsior1\ + -r NameService -ORBEndPoint iiop://localhost:10001 & + $ $TAO_ROOT/orbsvcs/Naming_Service/Naming_Service -o nsior2\ + -r NameService -ORBEndPoint iiop://localhost:10002 & + $ ./client -p file://nsior1 -q file://nsior2 + + where the steps correspond to 1&2)starting the Naming Service + in redundant mode, 3) running the client. + Don't forget to kill the name servers after you are done. + + + +EXPECTED OUTPUT FOR THIS TEST +***************************** + +Redundancy test OK. + + + diff --git a/TAO/orbsvcs/tests/FT_Naming/Replication/Replication.mpc b/TAO/orbsvcs/tests/FT_Naming/Replication/Replication.mpc new file mode 100644 index 00000000000..d4a8d42c12c --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Replication/Replication.mpc @@ -0,0 +1,7 @@ +// -*- MPC -*- +// $Id$ + +project(*Client) : ftnaming { + exename = client +} + diff --git a/TAO/orbsvcs/tests/FT_Naming/Replication/client.cpp b/TAO/orbsvcs/tests/FT_Naming/Replication/client.cpp new file mode 100644 index 00000000000..0c948882670 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Replication/client.cpp @@ -0,0 +1,689 @@ +// $Id$ + +// ============================================================================ +// +// = DESCRIPTION +// This class implements a CORBA client for a redundant CosNaming +// Service using stubs generated by the TAO ORB IDL compiler. +// +// = AUTHORS +// Rich Seibel <seibel_r@ociweb.com> +// ============================================================================ + +#include "test_objectS.h" +#include "orbsvcs/CosNamingC.h" +#include "orbsvcs/Naming/Naming_Server.h" +#include "tao/debug.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_stdio.h" +#include "ace/High_Res_Timer.h" + +#if defined (_MSC_VER) +# pragma warning (disable : 4250) +#endif /* _MSC_VER */ + +class My_Test_Object : + public virtual POA_Test_Object +{ +public: + // = Initialization and termination methods. + My_Test_Object (CORBA::Short id = 0); + // Constructor. + + ~My_Test_Object (void); + // Destructor. + + // = Interface implementation accessor methods. + + void id (CORBA::Short id); + // Sets id. + + CORBA::Short id (void); + // Gets id. + +private: + short id_; +}; + +My_Test_Object::My_Test_Object (CORBA::Short id) + : id_ (id) +{ +} + +My_Test_Object::~My_Test_Object (void) +{ +} + +CORBA::Short +My_Test_Object::id (void) +{ + return id_; +} + +void +My_Test_Object::id (CORBA::Short id) +{ + id_ = id; +} + + +// This function runs the test. + +int +ACE_TMAIN(int argc, ACE_TCHAR *argv[]) +{ + int c_breadth = 4; + int c_depth = 4; + int o_breadth = 4; + ACE_TCHAR *ns1ref = 0; + ACE_TCHAR *ns2ref = 0; + int test_runs = 100; + + ACE_Get_Opt get_opts (argc, argv, ACE_TEXT ("b:d:o:p:q:t:")); + int c; + int i; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'b': + i = ACE_OS::atoi(get_opts.opt_arg ()); + if (i<2) + { + ACE_ERROR((LM_ERROR, + ACE_TEXT ("Invalid breadth, must be 2 or more\n"))); + ACE_OS::exit(1); + } + c_breadth = i; + break; + case 'd': + i = ACE_OS::atoi(get_opts.opt_arg ()); + if (i<2) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Invalid depth, must be 2 or more\n"))); + ACE_OS::exit (1); + } + c_depth = i; + break; + case 'o': + i = ACE_OS::atoi(get_opts.opt_arg ()); + if (i<2) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Invalid breadth, must be 2 or more\n"))); + ACE_OS::exit (1); + } + o_breadth = i; + break; + case 'p': + ns1ref = get_opts.opt_arg (); + break; + case 't': + i = ACE_OS::atoi (get_opts.opt_arg ()); + if (i<1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Invalid number of test runs. ") + ACE_TEXT ("Must be 1 or more\n"))); + ACE_OS::exit (1); + } + test_runs = i; + break; + case 'q': + ns2ref = get_opts.opt_arg (); + break; + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Argument %c \n usage: %s") + ACE_TEXT (" [-b <breadth of context tree>]") + ACE_TEXT (" [-d <depth of context tree>]") + ACE_TEXT (" [-o <breadth of object tree>]") + ACE_TEXT (" [-t <number of performance test runs>]") + ACE_TEXT (" -p <ior of first name server>") + ACE_TEXT (" -q <ior of second name server>") + ACE_TEXT ("\n")), + -1); + } + + CosNaming::NamingContext_var root_context_1; + CosNaming::NamingContext_var root_context_2; + + try + { + // Initialize orb + CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); + + // ior's are specified for the name servers through a commandline + // option or a file. + + // Resolve the first name server + + CORBA::Object_var ns1obj = orb->string_to_object ( + ACE_TEXT_ALWAYS_CHAR (ns1ref)); + + if (CORBA::is_nil (ns1obj.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("invalid ior <%s>\n"), + ns1ref), + -1); + root_context_1 = CosNaming::NamingContext::_narrow (ns1obj.in ()); + + // Resolve the second name server + + CORBA::Object_var ns2obj = orb->string_to_object ( + ACE_TEXT_ALWAYS_CHAR (ns2ref)); + + if (CORBA::is_nil (ns2obj.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("invalid ior <%s>\n"), + ns2ref), + -1); + root_context_2 = CosNaming::NamingContext::_narrow (ns2obj.in ()); + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("Unable to resolve name servers")); + return -1; + } + + // Create a bunch of objects in one context + // Note: strings to the naming service must be char, not wchar + try + { + // Bind one context level under root. + CosNaming::Name level1; + level1.length (1); + level1[0].id = CORBA::string_dup ("level1_context"); + CosNaming::NamingContext_var level1_context; + level1_context = root_context_1->bind_new_context (level1); + + for (i=0; i<o_breadth; i++) + { + // Instantiate a dummy object and bind it under the new context. + My_Test_Object *impl1 = new My_Test_Object (i+1); + Test_Object_var obj1 = impl1->_this (); + impl1->_remove_ref (); + + level1.length (2); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "obj_%d", i); + level1[1].id = CORBA::string_dup (wide_name); + root_context_1->bind (level1, obj1.in ()); + + // See if the newly bound object is available in the + // replica + try { + CORBA::Object_var obj1_on_replica = + root_context_2->resolve (level1); + } + catch (const CosNaming::NamingContext::NotFound& ex) + { + ex._tao_print_exception ("Unable to resolve object from replica.\n"); + + // Try again... + try { + CORBA::Object_var obj1_on_replica = + root_context_2->resolve (level1); + // We did find the object on the replica, but only after a wait. + // This would be caused by a race condition to access the variable. + ACE_ERROR ((LM_ERROR, + "Object appeared after a short wait.\n")); + } + catch (const CosNaming::NamingContext::NotFound& second_ex) + { + second_ex._tao_print_exception ("It really is not there. Failing...\n"); + return -1; + } + } + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("Unable to create a lot of objects")); + return -1; + } + + // Create a deep context tree + try + { + CosNaming::NamingContext_var next_context = root_context_1; + for (i=0; i<c_depth; i++) + { + // Bind level1 context under root. + CosNaming::Name deep; + deep.length (1); + char deep_name[16]; + ACE_OS::sprintf(deep_name, "deep_%d", i); + deep[0].id = CORBA::string_dup (deep_name); + CosNaming::NamingContext_var deep_context; + deep_context = next_context->bind_new_context (deep); + next_context = deep_context; + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("Unable to create deep context")); + return -1; + } + + // Create a wide context tree + try + { + for (i=0; i<c_breadth; i++) + { + // Bind all level of context under root. + CosNaming::Name wide; + wide.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "wide_%d", i); + wide[0].id = CORBA::string_dup (wide_name); + CosNaming::NamingContext_var wide_context; + wide_context = root_context_1->bind_new_context (wide); + + try { + // Check if the new context is available in the replica + CORBA::Object_var obj1_on_replica = + root_context_2->resolve (wide); + // Make sure it is a context + CosNaming::NamingContext_var nc = + CosNaming::NamingContext::_narrow (obj1_on_replica); + } + catch (const CosNaming::NamingContext::NotFound& ex) + { + ex._tao_print_exception ("Unable to resolve wide context object from replica.\n"); + + // Try again to see if it just was a race condition + try { + CORBA::Object_var obj1_on_replica = + root_context_2->resolve (wide); + // We did find the object on the replica, but only after a wait. + // This would be caused by a race condition to access the variable. + ACE_ERROR ((LM_ERROR, + "Object appeared after a short wait.\n")); + } + catch (const CosNaming::NamingContext::NotFound& second_ex) + { + second_ex._tao_print_exception ("It really is not there. Failing...\n"); + return -1; + } + } + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("Unable to create wide context")); + return -1; + } + + // Delete three selected things, one from each tree + try { + // Remove the second to last object from the Naming Context + CosNaming::Name wide1; + wide1.length (2); + wide1[0].id = CORBA::string_dup ("level1_context"); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "obj_%d", o_breadth-2); + wide1[1].id = CORBA::string_dup (wide_name); + root_context_1->unbind (wide1); + + bool retried = false; + // Make sure it is gone from the replica + try { + CORBA::Object_var obj1_on_replica = + root_context_2->resolve (wide1); + + // An exception should be thrown by the above or + // there is an error. This means the replica did + // not register the loss of the context. + ACE_ERROR ((LM_ERROR, + "Unbound deep context not removed from replica. Trying again...\n")); + retried = true; // Mark this so it can be reported in catch block. + obj1_on_replica = + root_context_2->resolve (wide1); + ACE_ERROR_RETURN ((LM_ERROR, + "Unbound context not removed from on retry\n"), + -1); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Not on replica --- as it should be. + if (retried) // Was found on the retry + ACE_ERROR ((LM_ERROR, + "Was removed after short wait.\n")); + } + + // Remove the second to last context from the wide root Naming Context + CosNaming::Name wide2; + wide2.length (1); + ACE_OS::sprintf(wide_name, "wide_%d", c_breadth-2); + wide2[0].id = CORBA::string_dup (wide_name); + CORBA::Object_var result_obj_ref = root_context_1->resolve (wide2); + CosNaming::NamingContext_var result_object = + CosNaming::NamingContext::_narrow (result_obj_ref.in ()); + if (CORBA::is_nil (result_object.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Problems with resolving wide context ") + ACE_TEXT ("- nil object ref.\n")), + -1); + result_object->destroy(); + root_context_1->unbind (wide2); + + // Remove the last context from the deep Naming Context + CosNaming::Name deep; + deep.length (c_depth); + char deep_name[16]; + for (i=0; i<c_depth; i++) + { + ACE_OS::sprintf(deep_name, "deep_%d", i); + deep[i].id = CORBA::string_dup (deep_name); + } + result_obj_ref = root_context_1->resolve (deep); + result_object = + CosNaming::NamingContext::_narrow (result_obj_ref.in ()); + if (CORBA::is_nil (result_object.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Problems with resolving deep context ") + ACE_TEXT ("- nil object ref.\n")), + -1); + result_object->destroy(); + root_context_1->unbind (deep); + + retried = false; + // Make sure it is gone from the replica + try { + CORBA::Object_var obj1_on_replica = + root_context_2->resolve (deep); + + // An exception should be thrown by the above or + // there is an error. This means the replica did + // not register the loss of the context. + ACE_ERROR ((LM_ERROR, + "Unbound deep context not removed from replica. Trying again...\n")); + retried = true; // Mark this so it can be reported in catch block. + obj1_on_replica = + root_context_2->resolve (deep); + ACE_ERROR_RETURN ((LM_ERROR, + "Unbound context not removed from on retry\n"), + -1); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Not on replica --- as it should be. + if (retried) // Was found on the retry + ACE_ERROR ((LM_ERROR, + "Was removed after short wait.\n")); + } + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("Unable to delete objects")); + return -1; + } + + // Now use the other name server to access 3 objects next to the + // deleted objects and the 3 deleted objects + try + { + // Access the last object from the Naming Context + CosNaming::Name wide; + wide.length (2); + wide[0].id = CORBA::string_dup ("level1_context"); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "obj_%d", o_breadth-1); + wide[1].id = CORBA::string_dup (wide_name); + CORBA::Object_var result_obj_ref = root_context_2->resolve (wide); + Test_Object_var result_object = Test_Object::_narrow (result_obj_ref.in ()); + if (CORBA::is_nil (result_object.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Problems with resolving object from ") + ACE_TEXT ("redundant server - nil object ref.\n")), + -1); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ( + "Unable to resolve object from redundant server")); + return -1; + } + + try + { + // Access the deleted second to last object from the Naming Context + CosNaming::Name wide; + wide.length (2); + wide[0].id = CORBA::string_dup ("level1_context"); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "obj_%d", o_breadth-2); + wide[1].id = CORBA::string_dup (wide_name); + CORBA::Object_var result_obj_ref = root_context_2->resolve (wide); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Problems with resolving object from ") + ACE_TEXT ("redundant server - deleted object found.\n")), + -1); + } + catch (const CosNaming::NamingContext::NotFound& ex) + { + // expect exception since the context was deleted. + // Make sure the right exception reason is provided. + if (ex.why != CosNaming::NamingContext::missing_node) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Wrong exception returned during resolve.\n")), + -1); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("Wrong exception type returned from resolve.\n")); + return -1; + } + try + { + // Access the last context from the wide Naming Context + CosNaming::Name wide; + wide.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "wide_%d", c_breadth-1); + wide[0].id = CORBA::string_dup (wide_name); + CORBA::Object_var result_obj_ref = root_context_2->resolve (wide); + CosNaming::NamingContext_var result_object = + CosNaming::NamingContext::_narrow (result_obj_ref.in ()); + if (CORBA::is_nil (result_object.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Problems with resolving wide context from ") + ACE_TEXT ("redundant server - nil object ref.\n")), + -1); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Expected exception + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Unexpected Exception received.\n")); + return -1; + } + + try + { + // Access the deleted second to last object from the Naming Context + CosNaming::Name wide; + wide.length (2); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "wide_%d", c_breadth-2); + wide[0].id = CORBA::string_dup (wide_name); + CORBA::Object_var result_obj_ref = root_context_2->resolve (wide); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Problems with resolving wide context from ") + ACE_TEXT ("redundant server - deleted object found.\n")), + -1); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Expected exception + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Unexpected Exception received.\n")); + return -1; + } + + try + { + // Access the deleted last context from the deep Naming Context + CosNaming::Name deep; + deep.length (c_depth); + char deep_name[16]; + for (i=0; i<c_depth; i++) + { + ACE_OS::sprintf(deep_name, "deep_%d", i); + deep[i].id = CORBA::string_dup (deep_name); + } + CORBA::Object_var result_obj_ref = root_context_1->resolve (deep); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Problems with resolving deep context from ") + ACE_TEXT ("redundant server - deleted object found.\n")), + -1); + } + catch (const CosNaming::NamingContext::NotFound&) + { + // Expected exception + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ("Unexpected Exception received resolving ") + ACE_TEXT ("deep cxt from redundant server.\n")); + return -1; + } + + try + { + // Access the second to last object from the Naming Context + CosNaming::Name deep; + deep.length (c_depth-1); + char deep_name[16]; + for (i=0; i<c_depth-1; i++) + { + ACE_OS::sprintf(deep_name, "deep_%d", i); + deep[i].id = CORBA::string_dup (deep_name); + } + CORBA::Object_var result_obj_ref = root_context_1->resolve (deep); + CosNaming::NamingContext_var result_object = + CosNaming::NamingContext::_narrow (result_obj_ref.in ()); + if (CORBA::is_nil (result_object.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Problems with resolving deep context from ") + ACE_TEXT ("redundant server - nil object ref.\n")), + -1); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception ( + ACE_TEXT ( + "Unable to resolve deep context from redundant server")); + return -1; + } + + // TODO: Cleanup namespace + + + // TODO: Create object groups and bind them. Check the replica. + + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Redundancy test OK.\n") + ACE_TEXT ("Starting performance tests.\n"))); + + // Test performance of binding a bunch of objects in one context + try + { + // Bind one context level under root. + CosNaming::Name level1; + level1.length (1); + level1[0].id = CORBA::string_dup ("perf_context"); + CosNaming::NamingContext_var perf_context; + perf_context = root_context_1->bind_new_context (level1); + + // Instantiate a dummy object and bind it under the new context. + My_Test_Object *impl1 = new My_Test_Object (i+1); + Test_Object_var obj1 = impl1->_this (); + impl1->_remove_ref (); + + ACE_High_Res_Timer::global_scale_factor_type gsf = + ACE_High_Res_Timer::global_scale_factor (); + + ACE_hrtime_t start = ACE_OS::gethrtime (); + + // Test how long it takes to bind + for (i=0; i<test_runs; i++) + { + level1.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "obj_%d", i); + level1[0].id = CORBA::string_dup (wide_name); + perf_context->bind (level1, obj1.in ()); + } + + ACE_hrtime_t elapsed_time = ACE_OS::gethrtime () - start; + // convert to microseconds + ACE_UINT32 usecs = ACE_UINT32(elapsed_time / gsf); + double secs = usecs / 1000000.0; + + ACE_DEBUG ((LM_DEBUG, + "Bound %i objects in %.2f secs\n", + test_runs, secs)); + + // Test how long it takes to resolve + start = ACE_OS::gethrtime (); + for (i=0; i<test_runs; i++) + { + level1.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "obj_%d", i); + level1[0].id = CORBA::string_dup (wide_name); + CORBA::Object_var result_obj_ref = perf_context->resolve (level1); + } + + elapsed_time = ACE_OS::gethrtime () - start; + // convert to microseconds + usecs = ACE_UINT32(elapsed_time / gsf); + secs = ((ACE_INT32) usecs) / 1000000.0; + + ACE_DEBUG ((LM_DEBUG, + "Resolved %i objects in %.2f secs\n", + test_runs, secs)); + + // Test how long it takes to unbind + start = ACE_OS::gethrtime (); + for (i=0; i<test_runs; i++) + { + level1.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "obj_%d", i); + level1[0].id = CORBA::string_dup (wide_name); + perf_context->unbind (level1); + } + + elapsed_time = ACE_OS::gethrtime () - start; + // convert to microseconds + usecs = ACE_UINT32(elapsed_time / gsf); + secs = ((ACE_INT32) usecs) / 1000000.0; + + ACE_DEBUG ((LM_DEBUG, + "Unbound %i objects in %.2f secs\n", + test_runs, secs)); + + + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("ERROR: Exception during performance test.\n")); + return -1; + } + + + return 0; + +} diff --git a/TAO/orbsvcs/tests/FT_Naming/Replication/run_test.pl b/TAO/orbsvcs/tests/FT_Naming/Replication/run_test.pl new file mode 100755 index 00000000000..3aa67068b69 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Replication/run_test.pl @@ -0,0 +1,212 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +# This is a Perl script that runs a Naming Service test. It starts +# all the servers and clients as necessary. + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::TestTarget; +use Cwd; + +$startdir = getcwd(); + +$quiet = 0; + +# check for -q flag +if ($ARGV[0] eq '-q') { + $quiet = 1; +} + +my $test = PerlACE::TestTarget::create_target (1) || die "Create target 1 failed\n"; + +# Variables for command-line arguments to client and server +# executables. +$hostname = $test->HostName (); + +$ns_orb_port1 = 10001 + $test->RandomPort (); +$ns_orb_port2 = 10002 + $test->RandomPort (); +$ns_endpoint1 = "iiop://$hostname:$ns_orb_port1"; +$ns_endpoint2 = "iiop://$hostname:$ns_orb_port2"; + +$naming_persistence_dir = "NameService"; +$groups_persistence_dir = "Groups"; + +$primary_iorfile = "$naming_persistence_dir/ns_replica_primary.ior"; +$combined_ns_iorfile = "combined_ns.ior"; +$nm_iorfile = "nm.ior"; + +print STDERR "$primary_iorfile\n"; + +## Allow the user to determine where the persistent file will be located +## just in case the current directory is not suitable for locking. +## We can't change the name of the persistent file because that is not +## sufficient to work around locking problems for Tru64 when the current +## directory is NFS mounted from a system that does not properly support +## locking. +foreach my $possible ($ENV{TMPDIR}, $ENV{TEMP}, $ENV{TMP}) { + if (defined $possible && -d $possible) { + if (chdir($possible)) { + last; + } + } +} + +my $test_combined_ns_iorfile = $test->LocalFile ($combined_ns_iorfile); +my $test_nm_iorfile = $test->LocalFile ($nm_iorfile); +my $test_primary_iorfile = $test->LocalFile ($primary_iorfile); + +$status = 0; + +sub clean_persistence_dir +{ + chdir $naming_persistence_dir; + opendir(THISDIR, "."); + @allfiles = grep(!/^\.\.?$/, readdir(THISDIR)); + closedir(THISDIR); + foreach $tmp (@allfiles){ + $test->DeleteFile ($tmp); + } + chdir ".."; +} + +print "INFO: Running the test in ", getcwd(), "\n"; + +sub clean_persistence_dir($$) +{ + my $target = shift; + my $directory_name = shift; + + chdir $directory_name; + opendir(THISDIR, "."); + @allfiles = grep(!/^\.\.?$/, readdir(THISDIR)); + closedir(THISDIR); + foreach $tmp (@allfiles){ + $target->DeleteFile ($tmp); + } + chdir ".."; +} + +# Make sure that the directory to use to hold the persistence data +# exists and is cleaned out. +sub init_persistence_directory($$) +{ + my $target = shift; + my $directory_name = shift; + + if ( ! -d $directory_name ) { + mkdir ($directory_name, 0777); + } else { + clean_persistence_dir ($target, $directory_name); + } +} + + +# Run two Naming Servers and one client. Client uses iors +# in files to find the individual copies of the Naming Servers. + +my $args = "-ORBEndPoint $ns_endpoint1 " . + "-m 0 " . + "-r $naming_persistence_dir " . + "-v $groups_persistence_dir " . + "-n 100 " . + "--primary"; +my $prog = "$startdir/../../../Naming_Service/tao_ft_naming"; + +print STDERR "Starting Primary: $prog $args\n"; + +$NS1 = $test->CreateProcess ("$prog", "$args"); + +$test->DeleteFile ($primary_iorfile); + +init_persistence_directory ($test, $naming_persistence_dir); +init_persistence_directory ($test, $groups_persistence_dir); + +$NS1->Spawn (); + +if ($test->WaitForFileTimed ($primary_iorfile, + $test->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$test_primary_iorfile>\n"; + $NS1->Kill (); $NS1->TimedWait (1); + exit 1; +} + +$args = "-ORBEndPoint $ns_endpoint2 " . + "-g $nm_iorfile " . + "-c $combined_ns_iorfile " . + "-m 0 " . + "-n 100 " . + "-r $naming_persistence_dir " . + "-v $groups_persistence_dir " . + "--backup"; + +$prog = "$startdir/../../../Naming_Service/tao_ft_naming"; + +print STDERR "Starting Backup: $prog $args\n"; + +$NS2 = $test->CreateProcess ("$prog", "$args"); + +$test->DeleteFile ($combined_ns_iorfile); +$test->DeleteFile ($nm_iorfile); + +$NS2->Spawn (); + +if ($test->WaitForFileTimed ($combined_ns_iorfile, + $test->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$test_combined_ns_iorfile>\n"; + $NS2->Kill (); $NS2->TimedWait (1); + exit 1; +} + +# Use corbaloc to access each individual name service without +# using the combined IOR. +$args = "-p corbaloc:iiop:$hostname:$ns_orb_port1/NameService " . + "-q corbaloc:iiop:$hostname:$ns_orb_port2/NameService " . + "-b 4 " . + "-d 4 " . + "-t 100"; +$prog = "$startdir/client"; + +print STDERR "Starting Client: $prog $args\n"; + +$CL = $test->CreateProcess ("$prog", "$args"); + +$client = $CL->SpawnWaitKill ($test->ProcessStartWaitInterval()); + +if ($client != 0) { + print STDERR "ERROR: client returned $client\n"; + $status = 1; +} + +# Kill the first server and make sure the tree can be accessed +# by the nslist +print STDERR "Killing the primary naming service\n"; +$NS1->Kill (); + +print STDERR "Printing Naming Tree from combined Name Service pair.\n"; + +$prog = "$startdir/../../../../utils/nslist/tao_nslist"; +$args = "--ns file://$combined_ns_iorfile"; + +$NSL = $test->CreateProcess("$prog", "$args"); + + +$out = $NSL->SpawnWaitKill (60); + +# Now kill off the backup +$NS2->Kill (); + +$test->DeleteFile ($primary_iorfile); +$test->DeleteFile ($combined_ns_iorfile); + +# Clean out the persistence dir after the test completes +clean_persistence_dir ($test, $naming_persistence_dir); +clean_persistence_dir ($test, $groups_persistence_dir); + +rmdir ($naming_persistence_dir); +rmdir ($groups_persistence_dir); + +exit $status; diff --git a/TAO/orbsvcs/tests/FT_Naming/Replication/test_object.idl b/TAO/orbsvcs/tests/FT_Naming/Replication/test_object.idl new file mode 100644 index 00000000000..4737f6dc6c8 --- /dev/null +++ b/TAO/orbsvcs/tests/FT_Naming/Replication/test_object.idl @@ -0,0 +1,11 @@ +// $Id$ + +interface Test_Object +{ + // = TITLE + // This is a simple interface that tests the Naming Service. + + attribute short id; + // This provides an easy way to differentiate objects if each + // objects is served by a separate servant. +}; diff --git a/TAO/orbsvcs/tests/ImplRepo/README b/TAO/orbsvcs/tests/ImplRepo/README index d55a9c2f33d..91042fca6f3 100644 --- a/TAO/orbsvcs/tests/ImplRepo/README +++ b/TAO/orbsvcs/tests/ImplRepo/README @@ -9,10 +9,27 @@ nt_service_ir same as above but runs ImplRepo as an NT service. nestea runs nestea client and server without ImplRepo. nestea_ir same as above but uses ImplRepo. both_ir combines airplane_ir and nestea_ir. -persistent_ir same as airplane_ir, but using persistent ImplRepo. - -The nt_service_ir test will work only on Win32 platforms. For the test to -run successfully, these conditions must be met: +persistent_ir same as airplane_ir, but using persistent + "-x <file>" flag for the ImplRepo. +persistent_ir_hash same as persistent_ir, but using "-p <file>" flag. +persistent_ir_registry same as persistent_ir, but using "-r" flag + (windows registry flag). +persistent_ir_shared same as persistent_ir, but using + "--directory <dir>" flag. +persistent_ft runs a primary and backup ImR Locator, verifying + persistence works in different scenarios of + the primary or backup being shutdown. Must also + pass the "-replica" command to run_test.pl for + this test to run. +failover runs a primary and backup ImR Locator, verifying + different scenarios of the primary or backup being + shutdown and clients, servers, activators, and + tao_imr activities being unaffected. Must also + pass the "-replica" command to run_test.pl for + this test to run. + +The nt_service_ir and persistent_ir_registry tests will work only on Win32 +platforms. For the test to run successfully, these conditions must be met: -- The user must be logged in as administrator, or have administrative priveleges (in order to register an NT service). diff --git a/TAO/orbsvcs/tests/ImplRepo/ReconnectServer/client.cpp b/TAO/orbsvcs/tests/ImplRepo/ReconnectServer/client.cpp index bc61035a1b9..114f0be51cc 100755 --- a/TAO/orbsvcs/tests/ImplRepo/ReconnectServer/client.cpp +++ b/TAO/orbsvcs/tests/ImplRepo/ReconnectServer/client.cpp @@ -118,10 +118,6 @@ ACE_TMAIN(int argc, ACE_TCHAR *argv[]) } CORBA::Object_var object = orb->resolve_initial_references ("RootPOA"); - PortableServer::POA_var rootPOA = PortableServer::POA::_narrow (object.in ()); - - PortableServer::POAManager_var poa_manager = rootPOA->the_POAManager (); - poa_manager->activate (); object = orb->string_to_object(ior_input_file); @@ -142,8 +138,6 @@ ACE_TMAIN(int argc, ACE_TCHAR *argv[]) task.wait (); - // Destroy the POA, waiting until the destruction terminates - rootPOA->destroy (1, 1); orb->destroy (); if (task.test_passed ()) diff --git a/TAO/orbsvcs/tests/ImplRepo/RestartServer/Messenger.idl b/TAO/orbsvcs/tests/ImplRepo/RestartServer/Messenger.idl new file mode 100644 index 00000000000..880e7790199 --- /dev/null +++ b/TAO/orbsvcs/tests/ImplRepo/RestartServer/Messenger.idl @@ -0,0 +1,18 @@ +// $Id$ + +// messenger.idl + +interface Messenger +{ + boolean send_message ( in string user_name, + in string subject, + inout string message ); + + // After replying, abort process in + // delay_secs seconds. + void abort ( in short delay_secs ); + + // Perform a graceful shutdown. + oneway void shutdown (); +}; + diff --git a/TAO/orbsvcs/tests/ImplRepo/RestartServer/MessengerClient.cpp b/TAO/orbsvcs/tests/ImplRepo/RestartServer/MessengerClient.cpp new file mode 100644 index 00000000000..7cd8c1d5d08 --- /dev/null +++ b/TAO/orbsvcs/tests/ImplRepo/RestartServer/MessengerClient.cpp @@ -0,0 +1,82 @@ +// $Id$ + +#include "MessengerC.h" +#include <iostream> +#include "ace/Get_Opt.h" +#include "ace/OS_NS_unistd.h" + +const ACE_TCHAR *ior = ACE_TEXT("file://Messenger.ior"); + +int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("k:")); + int c; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'k': + ior = get_opts.opt_arg (); + break; + + case '?': + default: + ACE_ERROR_RETURN ((LM_ERROR, + "usage: %s " + "-k <ior> " + "\n", + argv [0]), + -1); + } + // Indicates successful parsing of the command line + return 0; +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + try { + // Initialize orb + CORBA::ORB_var orb = CORBA::ORB_init( argc, argv ); + + if (parse_args (argc, argv) != 0) + return 1; + + // Destringify ior + CORBA::Object_var obj = orb->string_to_object( ior ); + if (CORBA::is_nil(obj.in())) { + std::cerr << "Nil Messenger reference" << std::endl; + return 1; + } + + // Narrow + Messenger_var messenger = Messenger::_narrow( obj.in() ); + if (CORBA::is_nil(messenger.in())) { + std::cerr << "Argument is not a Messenger reference" << std::endl; + return 1; + } + + CORBA::String_var message = CORBA::string_dup( "Hello!" ); + + messenger->send_message( "TAO User", "Test 1", message.inout() ); + + // Force server to abort to verify it will be brought + // back up when send_message() is called. + messenger->abort(2); + ACE_OS::sleep(4); + + ACE_DEBUG ((LM_INFO, + "(%P|%t) - Sending another message after abort of server\n")); + + messenger->send_message( "TAO User", "Test 2", message.inout() ); + + std::cout << "messages were sent" << std::endl; + } + catch(const CORBA::Exception& ex) { + std::cerr << "Client main() Caught CORBA::Exception: " << ex << std::endl; + return 1; + } + + return 0; +} diff --git a/TAO/orbsvcs/tests/ImplRepo/RestartServer/MessengerServer.cpp b/TAO/orbsvcs/tests/ImplRepo/RestartServer/MessengerServer.cpp new file mode 100644 index 00000000000..370144b98d7 --- /dev/null +++ b/TAO/orbsvcs/tests/ImplRepo/RestartServer/MessengerServer.cpp @@ -0,0 +1,117 @@ +// $Id$ + +// MessengerServer.cpp +// This version uses the Implementation Repository. + +#include "Messenger_i.h" +#include "Terminator.h" + +#include "tao/IORTable/IORTable.h" +#include "tao/PortableServer/Root_POA.h" + +#include <iostream> + +PortableServer::POA_ptr +createPOA(PortableServer::POA_ptr root_poa, const char* poa_name) +{ + PortableServer::LifespanPolicy_var life = + root_poa->create_lifespan_policy(PortableServer::PERSISTENT); + + PortableServer::IdAssignmentPolicy_var assign = + root_poa->create_id_assignment_policy(PortableServer::USER_ID); + + CORBA::PolicyList pols; + pols.length(2); + pols[0] = PortableServer::LifespanPolicy::_duplicate(life.in()); + pols[1] = PortableServer::IdAssignmentPolicy::_duplicate(assign.in()); + + PortableServer::POAManager_var mgr = root_poa->the_POAManager(); + PortableServer::POA_var poa = + root_poa->create_POA(poa_name, mgr.in(), pols); + + life->destroy(); + assign->destroy(); + + return poa._retn(); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + try { + CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); + + CORBA::Object_var obj = orb->resolve_initial_references("RootPOA"); + PortableServer::POA_var root_poa = PortableServer::POA::_narrow(obj.in()); + + PortableServer::POAManager_var mgr = root_poa->the_POAManager(); + + const char* poa_name = "MessengerService"; + + PortableServer::POA_var messenger_poa = createPOA(root_poa.in(), poa_name); + + Terminator terminator; + if (terminator.open (0) == -1) + ACE_ERROR_RETURN((LM_ERROR, + ACE_TEXT ("main Error opening terminator\n")),-1); + + PortableServer::Servant_var<Messenger_i> messenger_servant = + new Messenger_i(orb.in(), terminator); + + PortableServer::ObjectId_var object_id = + PortableServer::string_to_ObjectId("messenger_object"); + + // + // Activate the servant with the messenger POA, + // obtain its object reference, and get a + // stringified IOR. + // + messenger_poa->activate_object_with_id(object_id.in(), messenger_servant.in()); + + // + // Create binding between "MessengerService" and + // the messenger object reference in the IOR Table. + // Use a TAO extension to get the non imrified poa + // to avoid forwarding requests back to the ImR. + + TAO_Root_POA* tpoa = dynamic_cast<TAO_Root_POA*>(messenger_poa.in()); + obj = tpoa->id_to_reference_i(object_id.in(), false); + CORBA::String_var messenger_ior = orb->object_to_string(obj.in()); + obj = orb->resolve_initial_references("IORTable"); + IORTable::Table_var table = IORTable::Table::_narrow(obj.in()); + table->bind(poa_name, messenger_ior.in()); + + // + // This server is now ready to run. + // This version does not create an IOR + // file as demonstrated in the + // Developer's Guide. It assumes that + // users create IORs for the client using + // the tao_imr utility. + // + // + // Stop discarding requests. + // + mgr->activate(); + + std::cout << "Messenger server ready." << std::endl; + + orb->run(); + + std::cout << "Messenger server shutting down." << std::endl; + + root_poa->destroy(1,1); + orb->destroy(); + + ACE_Message_Block *mb; + ACE_NEW_RETURN(mb, ACE_Message_Block(0, ACE_Message_Block::MB_HANGUP), -1); + terminator.putq(mb); + terminator.wait(); + } + catch(const CORBA::Exception& ex) { + std::cerr << "Server main() Caught CORBA::Exception" << ex << std::endl; + return 1; + } + + return 0; +} diff --git a/TAO/orbsvcs/tests/ImplRepo/RestartServer/Messenger_i.cpp b/TAO/orbsvcs/tests/ImplRepo/RestartServer/Messenger_i.cpp new file mode 100644 index 00000000000..a701f84a1f5 --- /dev/null +++ b/TAO/orbsvcs/tests/ImplRepo/RestartServer/Messenger_i.cpp @@ -0,0 +1,53 @@ +/* -*- C++ -*- $Id$ */ + +// ****** Code generated by the The ACE ORB (TAO) IDL Compiler ******* +// TAO and the TAO IDL Compiler have been developed by the Center for +// Distributed Object Computing at Washington University, St. Louis. +// +// Information about TAO is available at: +// http://www.cs.wustl.edu/~schmidt/TAO.html + +#include "Messenger_i.h" +#include "Terminator.h" + +#include <iostream> + +// Implementation skeleton constructor +Messenger_i::Messenger_i (CORBA::ORB_ptr orb, Terminator &terminator) + : orb_ (CORBA::ORB::_duplicate (orb)) + , message_count_ (0) + , terminator_ (terminator) +{ +} + +// Implementation skeleton destructor +Messenger_i::~Messenger_i (void) +{ +} + +CORBA::Boolean Messenger_i::send_message ( + const char * user_name, + const char * subject, + char *& message) +{ + std::cout << "Message count: " << message_count_++ << std::endl; + std::cout << "Message from: " << user_name << std::endl + << "Subject: " << subject << std::endl + << "Message: " << message << std::endl; + return 1; +} + +void +Messenger_i::abort (CORBA::Short delay_secs) +{ + ACE_Message_Block *mb = 0; + ACE_NEW(mb, ACE_Message_Block(2)); + ACE_OS::sprintf(mb->wr_ptr (), "%d", delay_secs); + terminator_.putq(mb); +} + +void +Messenger_i::shutdown (void) +{ + this->orb_->shutdown (0); +} diff --git a/TAO/orbsvcs/tests/ImplRepo/RestartServer/Messenger_i.h b/TAO/orbsvcs/tests/ImplRepo/RestartServer/Messenger_i.h new file mode 100644 index 00000000000..45e7389c8df --- /dev/null +++ b/TAO/orbsvcs/tests/ImplRepo/RestartServer/Messenger_i.h @@ -0,0 +1,43 @@ +/* -*- C++ -*- $Id$ */ + +#ifndef MESSENGERI_H_ +#define MESSENGERI_H_ + +#include "MessengerS.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +class Terminator; + +//Class Messenger_i +class Messenger_i : public virtual POA_Messenger +{ +public: + //Constructor + Messenger_i (CORBA::ORB_ptr orb, Terminator &terminator); + + //Destructor + virtual ~Messenger_i (void); + + virtual CORBA::Boolean send_message ( + const char * user_name, + const char * subject, + char *& message); + + virtual void abort (CORBA::Short delay_secs); + + virtual void shutdown (void); + +private: + /// Use an ORB reference to shutdown the application. + CORBA::ORB_var orb_; + + int message_count_; + + Terminator& terminator_; +}; + + +#endif /* MESSENGERI_H_ */ diff --git a/TAO/orbsvcs/tests/ImplRepo/RestartServer/README b/TAO/orbsvcs/tests/ImplRepo/RestartServer/README new file mode 100644 index 00000000000..f69485fb4c1 --- /dev/null +++ b/TAO/orbsvcs/tests/ImplRepo/RestartServer/README @@ -0,0 +1,10 @@ +$Id$ + +This test verifies that if a server launched by the ImR activator is terminated, +then it will be relaunched transparently by the ORB if the client makes another +request if -ORBForwardOnTransientLimit and -ORBForwardOnReplyClosedLimit options +are used. + +Note that TAO does not have a way of knowing if server actually processed the +request, so that the CORBA "at most once" guarantee may be violated if +-ORBForwardOnReplyClosedLimit is used. diff --git a/TAO/orbsvcs/tests/ImplRepo/RestartServer/RestartServer.mpc b/TAO/orbsvcs/tests/ImplRepo/RestartServer/RestartServer.mpc new file mode 100644 index 00000000000..c619da302e2 --- /dev/null +++ b/TAO/orbsvcs/tests/ImplRepo/RestartServer/RestartServer.mpc @@ -0,0 +1,37 @@ +// $Id$ + +project(*idl): taoidldefaults { + IDL_Files { + Messenger.idl + } + custom_only = 1 +} + +project(*Server): taoserver, iortable, avoids_minimum_corba, avoids_corba_e_micro { + exename = MessengerServer + after += *idl + Source_Files { + Messenger_i.cpp + MessengerServer.cpp + Terminator.cpp + } + Source_Files { + MessengerC.cpp + MessengerS.cpp + } + IDL_Files { + } +} + +project(*Client): taoclient, anytypecode, avoids_minimum_corba { + exename = MessengerClient + after += *idl + Source_Files { + MessengerClient.cpp + } + Source_Files { + MessengerC.cpp + } + IDL_Files { + } +} diff --git a/TAO/orbsvcs/tests/ImplRepo/RestartServer/Terminator.cpp b/TAO/orbsvcs/tests/ImplRepo/RestartServer/Terminator.cpp new file mode 100644 index 00000000000..23b4a0475e4 --- /dev/null +++ b/TAO/orbsvcs/tests/ImplRepo/RestartServer/Terminator.cpp @@ -0,0 +1,40 @@ +/* -*- C++ -*- $Id$ */ + +#include "Terminator.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_unistd.h" + +int +Terminator::open(void*) +{ + if(this->activate (THR_NEW_LWP | THR_JOINABLE, + 1) == -1) + { + ACE_ERROR_RETURN((LM_ERROR, + ACE_TEXT("Terminator::open Error spawning thread %p\n"), + "err="), + -1); + } + return 0; +} + +int +Terminator::svc() +{ + while (1) + { + ACE_Message_Block* mb; + ACE_ASSERT(this->getq(mb) != -1); + if (mb->msg_type () == ACE_Message_Block::MB_HANGUP) + { + mb->release (); + break; + } + int delay_secs = ACE_OS::atoi(mb->rd_ptr()); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t|%T) Terminator::svc() Sleeping %d seconds before aborting\n", delay_secs)); + ACE_OS::sleep(delay_secs); + ACE_OS::abort(); + } + return 0; +} diff --git a/TAO/orbsvcs/tests/ImplRepo/RestartServer/Terminator.h b/TAO/orbsvcs/tests/ImplRepo/RestartServer/Terminator.h new file mode 100644 index 00000000000..29be200f03e --- /dev/null +++ b/TAO/orbsvcs/tests/ImplRepo/RestartServer/Terminator.h @@ -0,0 +1,13 @@ +/* -*- C++ -*- $Id$ */ + +#include "ace/Task_T.h" + +class Terminator : public ACE_Task<ACE_MT_SYNCH> +{ + public: + + virtual int open(void*); + + virtual int svc(); +}; + diff --git a/TAO/orbsvcs/tests/ImplRepo/RestartServer/client.conf b/TAO/orbsvcs/tests/ImplRepo/RestartServer/client.conf new file mode 100644 index 00000000000..409ad4afe86 --- /dev/null +++ b/TAO/orbsvcs/tests/ImplRepo/RestartServer/client.conf @@ -0,0 +1,3 @@ +# $Id$ + +static Client_Strategy_Factory "-ORBForwardOnTransientLimit 20" diff --git a/TAO/orbsvcs/tests/ImplRepo/RestartServer/run_test.pl b/TAO/orbsvcs/tests/ImplRepo/RestartServer/run_test.pl new file mode 100755 index 00000000000..cc398aa4f03 --- /dev/null +++ b/TAO/orbsvcs/tests/ImplRepo/RestartServer/run_test.pl @@ -0,0 +1,245 @@ +# $Id$ + +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::TestTarget; + +$status = 0; +$debug_level = '0'; + +foreach $i (@ARGV) { + if ($i eq '-debug') { + $debug_level = '10'; + } +} + +my $extra_timeout = 45; + +my $c1 = PerlACE::TestTarget::create_target (1) || die "Create target 1 failed\n"; +my $imr = PerlACE::TestTarget::create_target (3) || die "Create target 3 failed\n"; +my $act = PerlACE::TestTarget::create_target (4) || die "Create target 4 failed\n"; +my $ti = PerlACE::TestTarget::create_target (5) || die "Create target 5 failed\n"; +my $si = PerlACE::TestTarget::create_target (6) || die "Create target 6 failed\n"; +my $sdn = PerlACE::TestTarget::create_target (7) || die "Create target 7 failed\n"; + +my $implrepo_server = "$ENV{TAO_ROOT}/orbsvcs/ImplRepo_Service/tao_imr_locator"; +my $imr_activator = "$ENV{TAO_ROOT}/orbsvcs/ImplRepo_Service/tao_imr_activator"; +my $tao_imr = "$ENV{ACE_ROOT}/bin/tao_imr"; + +$implrepo_ior = "implrepo.ior"; +$activator_ior = "activator.ior"; +$messenger_ior = "Messenger.ior"; + +# Use client strategy factory for one of retry parameters. +$c1_conf = "client.conf"; + +my $imr_imriorfile = $imr->LocalFile ($implrepo_ior); +my $act_imriorfile = $act->LocalFile ($implrepo_ior); +my $ti_imriorfile = $ti->LocalFile ($implrepo_ior); +my $si_imriorfile = $si->LocalFile ($implrepo_ior); +my $sdn_imriorfile = $sdn->LocalFile ($implrepo_ior); +my $act_actiorfile = $act->LocalFile ($activator_ior); +my $imr_srviorfile = $imr->LocalFile ($messenger_ior); +my $c1_srviorfile = $c1->LocalFile ($messenger_ior); +my $c1_conffile = $c1->LocalFile ($c1_conf); +my $si_srviorfile = $si->LocalFile ($messenger_ior); + +# Make sure the files are gone, so we can wait on them. +$imr->DeleteFile ($implrepo_ior); +$act->DeleteFile ($implrepo_ior); +$ti->DeleteFile ($implrepo_ior); +$si->DeleteFile ($implrepo_ior); +$sdn->DeleteFile ($implrepo_ior); +$act->DeleteFile ($activator_ior); +$imr->DeleteFile ($messenger_ior); +$c1->DeleteFile ($messenger_ior); +$si->DeleteFile ($messenger_ior); + +# Note : We don't actually use SVR, but we need a way to get the +# path to the -ExeSubDir +$SVR = $imr->CreateProcess ("MessengerServer", "-ORBdebuglevel $debug_level"); +my $server = $SVR->Executable (); +my $srv_server = $imr->LocalFile ($server); + +$IR = $imr->CreateProcess ($implrepo_server, "-d 1 ". + "orbobjrefstyle url ". + "-t 5 ". + "-o $imr_imriorfile"); +print ">>> " . $IR->CommandLine() . "\n"; + +$ACT = $act->CreateProcess ($imr_activator, "-d 1 ". + "orbobjrefstyle url ". + "-o $act_actiorfile ". + "-ORBInitRef ImplRepoService=file://$act_imriorfile"); + +$TI = $ti->CreateProcess ($tao_imr, "-ORBInitRef ImplRepoService=file://$ti_imriorfile ". + "add MessengerService ". + "-c \"$srv_server -orbobjrefstyle url -ORBUseIMR 1 -ORBInitRef ImplRepoService=file://$imr_imriorfile\" "); + + + +$SI = $si->CreateProcess ($tao_imr, "-ORBInitRef ImplRepoService=file://$si_imriorfile ". + "ior MessengerService ". + "-f $si_srviorfile "); + +$C1 = $c1->CreateProcess ("MessengerClient", "-k file://$c1_srviorfile ". + "-ORBForwardOnReplyClosedLimit 20 -ORBForwardDelay 500 ". + "-ORBSvcConf $c1_conffile -ORBdebuglevel $debug_level"); + +$SDN = $sdn->CreateProcess ("$tao_imr", "-ORBInitRef ImplRepoService=file://$sdn_imriorfile ". + "shutdown MessengerService"); + + +$IR_status = $IR->Spawn (); + +if ($IR_status != 0) { + print STDERR "ERROR: ImplRepo Service returned $IR_status\n"; + exit 1; +} + +if ($imr->WaitForFileTimed ($implrepo_ior,$imr->ProcessStartWaitInterval() + $extra_timeout) == -1) { + print STDERR "ERROR: cannot find file <$imr_imriorfile>\n"; + $IR->Kill (); $IR->TimedWait (1); + exit 1; +} + +if ($imr->GetFile ($implrepo_ior) == -1) { + print STDERR "ERROR: cannot retrieve file <$imr_imriorfile>\n"; + $IR->Kill (); $IR->TimedWait (1); + exit 1; +} +if ($act->PutFile ($implrepo_ior) == -1) { + print STDERR "ERROR: cannot set file <$act_imriorfile>\n"; + $IR->Kill (); $IR->TimedWait (1); + exit 1; +} +if ($ti->PutFile ($implrepo_ior) == -1) { + print STDERR "ERROR: cannot set file <$ti_imriorfile>\n"; + $IR->Kill (); $IR->TimedWait (1); + exit 1; +} +if ($si->PutFile ($implrepo_ior) == -1) { + print STDERR "ERROR: cannot set file <$si_imriorfile>\n"; + $IR->Kill (); $IR->TimedWait (1); + exit 1; +} +if ($sdn->PutFile ($implrepo_ior) == -1) { + print STDERR "ERROR: cannot set file <$sdn_imriorfile>\n"; + $IR->Kill (); $IR->TimedWait (1); + exit 1; +} + +print ">>> " . $ACT->CommandLine() . "\n"; +$ACT_status = $ACT->Spawn (); + +if ($ACT_status != 0) { + print STDERR "ERROR: ImR_Activator returned $ACT_status\n"; + exit 1; +} + +if ($act->WaitForFileTimed ($activator_ior,$act->ProcessStartWaitInterval() + $extra_timeout) == -1) { + print STDERR "ERROR: cannot find file <$act_actiorfile>\n"; + $IR->Kill (); $IR->TimedWait (1); + $ACT->Kill (); $ACT->TimedWait (1); + exit 1; +} + +print ">>> " . $TI->CommandLine() . "\n"; +# We want the tao_imr executable to be found exactly in the path +# given, without being modified by the value of -ExeSubDir. +# So, we tell its Process object to ignore the setting of -ExeSubDir. + +$TI->IgnoreExeSubDir (1); + +$TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval() + $extra_timeout); + +if ($TI_status != 0) { + print STDERR "ERROR: tao_imr returned $TI_status\n"; + $IR->Kill (); $IR->TimedWait (1); + $ACT->Kill (); $ACT->TimedWait (1); + exit 1; +} + +print ">>> " . $SI->CommandLine() . "\n"; +$SI->IgnoreExeSubDir (1); + + +$SI_status = $SI->SpawnWaitKill ($si->ProcessStartWaitInterval() + $extra_timeout); + +if ($SI_status != 0) { + print STDERR "ERROR: tao_imr returned $SI_status\n"; + $IR->Kill (); $IR->TimedWait (1); + $ACT->Kill (); $ACT->TimedWait (1); + exit 1; +} + +if ($si->WaitForFileTimed ($messenger_ior,$si->ProcessStartWaitInterval() + $extra_timeout) == -1) { + print STDERR "ERROR: cannot find file <$si_srviorfile>\n"; + $IR->Kill (); $IR->TimedWait (1); + $ACT->Kill (); $ACT->TimedWait (1); + exit 1; +} + +if ($si->GetFile ($messenger_ior) == -1) { + print STDERR "ERROR: cannot retrieve file <$si_srviorfile>\n"; + $IR->Kill (); $IR->TimedWait (1); + $ACT->Kill (); $ACT->TimedWait (1); + exit 1; +} +if ($c1->PutFile ($messenger_ior) == -1) { + print STDERR "ERROR: cannot set file <$c1_srviorfile>\n"; + $IR->Kill (); $IR->TimedWait (1); + $ACT->Kill (); $ACT->TimedWait (1); + exit 1; +} + + +print ">>> " . $C1->CommandLine() . "\n"; +$C1_status = $C1->SpawnWaitKill ($c1->ProcessStartWaitInterval() + $extra_timeout); + +if ($C1_status != 0) { + print STDERR "ERROR: Client1 returned $C1_status\n"; + $IR->Kill (); $IR->TimedWait (1); + $ACT->Kill (); $ACT->TimedWait (1); + exit 1; +} + +$SDN->IgnoreExeSubDir (1); +$SDN_status = $SDN->SpawnWaitKill ($sdn->ProcessStartWaitInterval() + $extra_timeout); + +if ($SDN_status != 0) { + print STDERR "ERROR: Shutdown returned $SDN_status\n"; + $IR->Kill (); $IR->TimedWait (1); + $ACT->Kill (); $ACT->TimedWait (1); + exit 1; +} + + +$IR_status = $IR->TerminateWaitKill ($imr->ProcessStopWaitInterval() + $extra_timeout); + +if ($IR_status != 0) { + print STDERR "ERROR: ImplRepo Server returned $IR_status\n"; + $status = 1; +} + +$ACT_status = $ACT->TerminateWaitKill ($act->ProcessStopWaitInterval() + $extra_timeout); + +if ($ACT_status != 0) { + print STDERR "ERROR: ImR_Activator returned $ACT_status\n"; + $status = 1; +} + +$imr->DeleteFile ($implrepo_ior); +$act->DeleteFile ($implrepo_ior); +$ti->DeleteFile ($implrepo_ior); +$si->DeleteFile ($implrepo_ior); +$sdn->DeleteFile ($implrepo_ior); +$act->DeleteFile ($activator_ior); +$imr->DeleteFile ($messenger_ior); +$c1->DeleteFile ($messenger_ior); +$si->DeleteFile ($messenger_ior); + +exit $status; diff --git a/TAO/orbsvcs/tests/ImplRepo/airplane_client_i.cpp b/TAO/orbsvcs/tests/ImplRepo/airplane_client_i.cpp index df7a00e9391..cd1f1ff6878 100644 --- a/TAO/orbsvcs/tests/ImplRepo/airplane_client_i.cpp +++ b/TAO/orbsvcs/tests/ImplRepo/airplane_client_i.cpp @@ -56,9 +56,10 @@ Airplane_Client_i::parse_args (void) // Retreives <count> paper airplanes from the server. -void +int Airplane_Client_i::get_planes (size_t count) { + int rc = 0; for (size_t i = 0; i < count; i++) { try @@ -72,8 +73,10 @@ Airplane_Client_i::get_planes (size_t count) { ACE_ERROR ((LM_ERROR, "Plane %d exception:\n", i)); ex._tao_print_exception ("get_planes"); + rc = 1; } } + return rc; } @@ -82,9 +85,7 @@ Airplane_Client_i::get_planes (size_t count) int Airplane_Client_i::run () { - this->get_planes (this->loop_count_); - - return 0; + return this->get_planes (this->loop_count_); } Airplane_Client_i::~Airplane_Client_i (void) diff --git a/TAO/orbsvcs/tests/ImplRepo/airplane_client_i.h b/TAO/orbsvcs/tests/ImplRepo/airplane_client_i.h index 5c949a386c1..67497a0720c 100644 --- a/TAO/orbsvcs/tests/ImplRepo/airplane_client_i.h +++ b/TAO/orbsvcs/tests/ImplRepo/airplane_client_i.h @@ -46,7 +46,7 @@ private: int parse_args (void); /// Ask the Paper Airplane Server for <count> planes. - void get_planes (size_t count); + int get_planes (size_t count); /// # of arguments on the command line. int argc_; diff --git a/TAO/orbsvcs/tests/ImplRepo/airplane_server_i.cpp b/TAO/orbsvcs/tests/ImplRepo/airplane_server_i.cpp index 58dd5d3959e..873ec9dde5e 100644 --- a/TAO/orbsvcs/tests/ImplRepo/airplane_server_i.cpp +++ b/TAO/orbsvcs/tests/ImplRepo/airplane_server_i.cpp @@ -17,7 +17,8 @@ const char SERVER_NAME[] = "airplane_server"; Airplane_Server_i::Airplane_Server_i (void) : server_impl_ (0), - ior_output_file_ (0) + ior_output_file_ (0), + server_name_(SERVER_NAME) { // Nothing } @@ -25,7 +26,7 @@ Airplane_Server_i::Airplane_Server_i (void) int Airplane_Server_i::parse_args (void) { - ACE_Get_Opt get_opts (this->argc_, this->argv_, ACE_TEXT("do:")); + ACE_Get_Opt get_opts (this->argc_, this->argv_, ACE_TEXT("do:s:")); int c; while ((c = get_opts ()) != -1) @@ -41,12 +42,16 @@ Airplane_Server_i::parse_args (void) "Unable to open %s for writing: %p\n", get_opts.opt_arg ()), -1); break; + case 's': // extension to the server name. + this->server_name_ = get_opts.opt_arg (); + break; case '?': // display help for use of the server. default: ACE_ERROR_RETURN ((LM_ERROR, "usage: %s" " [-d]" - " [-o] <ior_output_file>" + " [-o <ior_output_file>]" + " [-s <the server name>]" "\n", argv_ [0]), 1); @@ -59,10 +64,6 @@ Airplane_Server_i::parse_args (void) int Airplane_Server_i::init (int argc, ACE_TCHAR** argv) { - // Since the Implementation Repository keys off of the POA name, we need - // to use the SERVER_NAME as the POA's name. - const char *poa_name = SERVER_NAME; - try { // Initialize the ORB @@ -101,10 +102,12 @@ Airplane_Server_i::init (int argc, ACE_TCHAR** argv) policies[1] = this->root_poa_->create_lifespan_policy (PortableServer::PERSISTENT); + // Since the Implementation Repository keys off of the POA name, we need + // to use the server_name_ as the POA's name. this->airplane_poa_ = - this->root_poa_->create_POA (poa_name, - this->poa_manager_.in (), - policies); + this->root_poa_->create_POA (this->server_name_.c_str(), + this->poa_manager_.in (), + policies); // Creation of the new POA is over, so destroy the Policy_ptr's. for (CORBA::ULong i = 0; i < policies.length (); ++i) @@ -142,7 +145,7 @@ Airplane_Server_i::init (int argc, ACE_TCHAR** argv) IORTable::Table_var adapter = IORTable::Table::_narrow (obj.in ()); ACE_ASSERT(! CORBA::is_nil (adapter.in ())); - adapter->bind (poa_name, plain_ior.in ()); + adapter->bind (this->server_name_.c_str(), plain_ior.in ()); this->poa_manager_->activate (); diff --git a/TAO/orbsvcs/tests/ImplRepo/airplane_server_i.h b/TAO/orbsvcs/tests/ImplRepo/airplane_server_i.h index c3ffc51f973..1be339107b6 100644 --- a/TAO/orbsvcs/tests/ImplRepo/airplane_server_i.h +++ b/TAO/orbsvcs/tests/ImplRepo/airplane_server_i.h @@ -70,6 +70,9 @@ private: /// File where the IOR of the server object is stored. FILE *ior_output_file_; + + /// the server name + ACE_CString server_name_; }; #endif /* AIRPLANE_SERVER_I_H */ diff --git a/TAO/orbsvcs/tests/ImplRepo/run_test.pl b/TAO/orbsvcs/tests/ImplRepo/run_test.pl index 318943a5fc9..43edcf5be04 100755 --- a/TAO/orbsvcs/tests/ImplRepo/run_test.pl +++ b/TAO/orbsvcs/tests/ImplRepo/run_test.pl @@ -8,50 +8,90 @@ eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' ############################################################################### +use strict; use lib "$ENV{ACE_ROOT}/bin"; use PerlACE::TestTarget; use File::Copy; -$debug_level = '0'; +my $debug_level = '0'; +my $srv_debug_level = '0'; +my $test_debug_level = '2'; +my $num_srvr = 1; +my $replica = 0; +my $all_tests = 0; -foreach $i (@ARGV) { +foreach my $i (@ARGV) { if ($i eq '-debug') { $debug_level = '10'; + $srv_debug_level = '10'; + } + elsif ($i eq '-tdebug') { + $test_debug_level = 10; + } + elsif ($i eq '-tsilent') { + $test_debug_level = 0; + } + elsif ($i eq '-servers') { + $num_srvr = 3; + } + elsif ($i eq '-replica') { + $num_srvr = 2; + $replica = 1; + } + elsif ($i eq '-all') { + $all_tests = 1; } } -my $imr = PerlACE::TestTarget::create_target (1) || die "Create target 1 failed\n"; -my $act = PerlACE::TestTarget::create_target (2) || die "Create target 2 failed\n"; -my $ti = PerlACE::TestTarget::create_target (3) || die "Create target 3 failed\n"; -my $a_srv = PerlACE::TestTarget::create_target (4) || die "Create target 4 failed\n"; -my $a_cli = PerlACE::TestTarget::create_target (5) || die "Create target 5 failed\n"; -my $n_srv = PerlACE::TestTarget::create_target (6) || die "Create target 6 failed\n"; -my $n_cli = PerlACE::TestTarget::create_target (7) || die "Create target 7 failed\n"; -my $p_srv = PerlACE::TestTarget::create_target (8) || die "Create target 8 failed\n"; -my $bin_imr = PerlACE::TestTarget::create_target (9) || die "Create target 9 failed\n"; -my $bin_act = PerlACE::TestTarget::create_target (10) || die "Create target 10 failed\n"; +my $tgt_num = 0; +my $imr = PerlACE::TestTarget::create_target (++$tgt_num) || die "Create target $tgt_num failed\n"; +my $act = PerlACE::TestTarget::create_target (++$tgt_num) || die "Create target $tgt_num failed\n"; +my $ti = PerlACE::TestTarget::create_target (++$tgt_num) || die "Create target $tgt_num failed\n"; +my $n_srv = PerlACE::TestTarget::create_target (++$tgt_num) || die "Create target $tgt_num failed\n"; +my $n_cli = PerlACE::TestTarget::create_target (++$tgt_num) || die "Create target $tgt_num failed\n"; +my $bin_imr = PerlACE::TestTarget::create_target (++$tgt_num) || die "Create target $tgt_num failed\n"; +my $bin_act = PerlACE::TestTarget::create_target (++$tgt_num) || die "Create target $tgt_num failed\n"; +my @a_cli; +my @a_srv; +my @p_srv; +my $index; +for ($index = 0; $index < $num_srvr; ++$index) { + push(@a_cli, PerlACE::TestTarget::create_target (++$tgt_num)) || die "Create a_cli target $tgt_num failed\n"; + push(@a_srv, PerlACE::TestTarget::create_target (++$tgt_num)) || die "Create a_srv target $tgt_num failed\n"; + push(@p_srv, PerlACE::TestTarget::create_target (++$tgt_num)) || die "Create p_srv target $tgt_num failed\n"; +} + +my $replica_imr; +if ($replica) { + $replica_imr = PerlACE::TestTarget::create_target (++$tgt_num) || die "Create replica_imr target $tgt_num failed\n"; + $replica_imr->AddLibPath ("$ENV{ACE_ROOT}/lib"); +} $imr->AddLibPath ("$ENV{ACE_ROOT}/lib"); my $imriorfile = "imr_locator.ior"; my $actiorfile = "imr_activator.ior"; -my $airplaneiorfile = "airplane.ior"; +my $primaryiorfile = "ImR_ReplicaPrimary.ior"; +my $backupiorfile = "ImR_ReplicaBackup.ior"; +my $replica_imriorfile = "replica_imr_locator.ior"; my $nesteaiorfile = "nestea.ior"; -my $backing_store = "imr_backing_store.xml"; my $nestea_dat = "nestea.dat"; -my $a_cli_airplaneiorfile = $a_cli->LocalFile ($airplaneiorfile); +my $stdout_file = "test.out"; +my $stderr_file = "test.err"; + my $n_cli_nesteaiorfile = $n_cli->LocalFile ($nesteaiorfile); my $refstyle = " -ORBObjRefStyle URL"; +my $imr_refstyle = "";# = " -ORBObjRefStyle URL"; my $protocol = "iiop"; my $imr_host = $imr->HostName (); my $port = 12345; my $endpoint = "-ORBEndpoint " . "$protocol" . "://:" . $port; -$IMR = $imr->CreateProcess ("../../ImplRepo_Service/tao_imr_locator"); -$ACT = $act->CreateProcess ("../../ImplRepo_Service/tao_imr_activator"); -$TI = $ti->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_imr"); +my $IMR = $imr->CreateProcess ("../../ImplRepo_Service/tao_imr_locator"); +my $ACT = $act->CreateProcess ("../../ImplRepo_Service/tao_imr_activator"); +my $TI = $ti->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_imr"); # We want the tao_imr executable to be found exactly in the path # given, without being modified by the value of -ExeSubDir. @@ -59,79 +99,460 @@ $TI = $ti->CreateProcess ("$ENV{ACE_ROOT}/bin/tao_imr"); $TI->IgnoreExeSubDir (1); +my $replica_IMR; +if ($replica) { + $replica_IMR = $replica_imr->CreateProcess ("../../ImplRepo_Service/tao_imr_locator"); +} + +my @airplaneiorfile; +my @a_cli_airplaneiorfile; +for ($index = 0; $index < $num_srvr; ++$index) { + push(@airplaneiorfile, "airplane$index.ior"); + push(@a_cli_airplaneiorfile, $a_cli[$index]->LocalFile ($airplaneiorfile[$index])); +} + sub create_acli { - return $a_cli->CreateProcess ("airplane_client", " -k file://$a_cli_airplaneiorfile "); + my $select = shift; + return $a_cli[$select]->CreateProcess ("airplane_client", " -k file://$a_cli_airplaneiorfile[$select] "); } sub create_ncli { return $n_cli->CreateProcess ("nestea_client", " -k file://$n_cli_nesteaiorfile "); } -my $A_SRV = $a_srv->CreateProcess ("airplane_server"); -my $A_CLI = create_acli(); -my $N_SRV = $a_cli->CreateProcess ("nestea_server"); -my $N_CLI = create_ncli(); -my $P_SRV = $p_srv->CreateProcess ("persist server"); +my @A_SRV; +my @a_srv_name; +my @A_SRV_cmd; +my @imr_A_SRV_cmd; +my @P_SRV; +my @P_SRV_cmd; +my @imr_P_SRV_cmd; +for ($index = 0; $index < $num_srvr; ++$index) { + push(@a_srv_name, "airplane_server$index"); + push(@A_SRV, $a_srv[$index]->CreateProcess ("airplane_server")); + my $p_srv_name = "persist server$index"; + push(@P_SRV, $p_srv[$index]->CreateProcess ($p_srv_name)); + + push(@A_SRV_cmd, $A_SRV[$index]->Executable()); + push(@imr_A_SRV_cmd, $imr->LocalFile ($A_SRV_cmd[$index])); + push(@P_SRV_cmd, $P_SRV[$index]->Executable()); + push(@imr_P_SRV_cmd, $imr->LocalFile ($P_SRV_cmd[$index])); +} -my $A_SRV_cmd = $A_SRV->Executable(); -my $imr_A_SRV_cmd = $imr->LocalFile ($A_SRV_cmd); +my @A_CLI; +for ($index = 0; $index < $num_srvr; ++$index) { + push(@A_CLI, create_acli($index)); +} +my $N_SRV = $a_cli[0]->CreateProcess ("nestea_server"); +my $N_CLI = create_ncli(); my $N_SRV_cmd = $N_SRV->Executable(); my $imr_N_SRV_cmd = $imr->LocalFile ($N_SRV_cmd); -my $P_SRV_cmd = $P_SRV->Executable(); -my $imr_P_SRV_cmd = $imr->LocalFile ($P_SRV_cmd); -# The Tests +############################################################################### +# Helper subroutines +############################################################################### + +sub setup_repo +{ + my $repo_ref = shift; + my $the_imr = shift; + my $the_IMR = shift; + my $the_imriorfile = shift; + my $the_act = shift; + my $the_ACT = shift; + my $the_actiorfile = shift; + my $the_ti = shift; + my $the_TI = shift; + my $port = shift; + my $replication_role = shift; + my $the_replicaiorfile = shift; + my $explicit_act = shift; + + my $the_imr_imriorfile = $the_imr->LocalFile ($the_imriorfile); + my $the_act_imriorfile = $the_act->LocalFile ($the_imriorfile); + my $the_ti_imriorfile = $the_ti->LocalFile ($the_imriorfile); + my $the_act_actiorfile = $the_act->LocalFile ($the_actiorfile); + my $the_imr_replicaiorfile = $the_imr->LocalFile ($the_replicaiorfile); + + $repo_ref->{imr} = $the_imr; + $repo_ref->{IMR} = $the_IMR; + $repo_ref->{imriorfile} = $the_imriorfile; + $repo_ref->{imr_imriorfile} = $the_imr_imriorfile; + $repo_ref->{imr_endpoint_flag} = "-ORBEndpoint iiop://:$port "; + if ($replica) { + $repo_ref->{imr_backing_store} = "."; + $repo_ref->{imr_backing_store_flag} = + "--directory $repo_ref->{imr_backing_store} $replication_role "; + } + $repo_ref->{replicaiorfile} = $the_replicaiorfile; + $repo_ref->{imr_replicaiorfile} = $the_imr_replicaiorfile; + + $repo_ref->{act} = $the_act; + $repo_ref->{ACT} = $the_ACT; + $repo_ref->{actiorfile} = $the_actiorfile; + $repo_ref->{act_imriorfile} = $the_act_imriorfile; + $repo_ref->{act_actiorfile} = $the_act_actiorfile; + if (defined($explicit_act)) { + $repo_ref->{server_act_flag} = "-l $explicit_act "; + $repo_ref->{act_explicit_flag} = "-n $explicit_act "; + } + + $repo_ref->{ti} = $the_ti; + $repo_ref->{TI} = $the_TI; + $repo_ref->{ti_imriorfile} = $the_ti_imriorfile; +} ############################################################################### -sub airplane_test +sub cleanup_replication { - my $status = 0; + my $dir = shift; + if (!defined($dir)) { + $dir = "."; + } + + my $listings = "$dir/imr_listing.xml"; + my $fnd = 0; + if (open FILE, "<$listings") { + while (<FILE>) { + if ($_ =~ /fname="([^"]+)"?/) { + $fnd = 1; + my $file = "$dir/$1"; + test_info("deleting $file\n"); + $imr->DeleteFile ($file); + $imr->DeleteFile ($file . ".bak"); + } + } + close FILE; + } + +# If the primary listings file has been corrupt then perform the +# deletions from the backup file. + + if (!$fnd) { + if (open FILE, "<$listings" . ".bak") { + while (<FILE>) { + if ($_ =~ /fname="([^"]+)"?/) { + my $file = "$dir/$1"; + test_info("deleting $file\n"); + $imr->DeleteFile ($file); + $imr->DeleteFile ($file . ".bak"); + } + } + close FILE; + } + } + test_info("deleting $listings\n"); + $imr->DeleteFile ("$listings"); + $imr->DeleteFile ("$listings" . ".bak"); + $imr->DeleteFile ("$dir/$primaryiorfile"); + $imr->DeleteFile ("$dir/$backupiorfile"); +} - my $a_srv_airplaneiorfile = $a_srv->LocalFile ($airplaneiorfile); - $a_srv->DeleteFile ($airplaneiorfile); - $a_cli->DeleteFile ($airplaneiorfile); +############################################################################### - $A_SRV->Arguments ("-o $a_srv_airplaneiorfile $refstyle -ORBDebugLevel $debug_level"); - $A_SRV_status = $A_SRV->Spawn (); - if ($A_SRV_status != 0) { - print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; - return 1; +sub test_info { + if ($test_debug_level < 10) { + return; } - if ($a_srv->WaitForFileTimed ($airplaneiorfile,$a_srv->ProcessStartWaitInterval()) == -1) { - print STDERR "ERROR: cannot find file <$a_srv_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); - return 1; + + my $info = shift; + print "$info"; +} + +############################################################################### + +sub kill_imr +{ + $IMR->Kill (); $IMR->TimedWait (1); + if ($replica) { + $replica_IMR->Kill (); $replica_IMR->TimedWait (1); } - if ($a_srv->GetFile ($airplaneiorfile) == -1) { - print STDERR "ERROR: cannot retrieve file <$a_srv_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); - return 1; +} + +############################################################################### + +sub kill_act +{ + $ACT->Kill (); $ACT->TimedWait (1); +} + +############################################################################### + +sub add_servers +{ + my $repo_ref = shift; + my $iorfiles_ref = shift; + + for ($index = 0; $index < $num_srvr; ++$index) { + print "\n\nadding server $index using tao_imr\n"; + $repo_ref->[$index]->{TI}->Arguments ("-ORBInitRef ImplRepoService" . + "=file://$repo_ref->[$index]->{ti_imriorfile} $refstyle " . + "add $a_srv_name[$index] -c \"$imr_A_SRV_cmd[$index] " . + "-o $iorfiles_ref->[$index] -s $a_srv_name[$index]\" " . + "$repo_ref->[$index]->{server_act_flag} "); + my $TI_status = $repo_ref->[$index]->{TI}->SpawnWaitKill ( + $repo_ref->[$index]->{ti}->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr ($index) returned $TI_status\n"; + kill_act(); + kill_imr(); + return 1; + } + print "added server $index with the locator using tao_imr\n"; } - if ($a_cli->PutFile ($airplaneiorfile) == -1) { - print STDERR "ERROR: cannot set file <$a_cli_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); - return 1; + return 0; +} + +############################################################################### + +sub add_servers_again +{ + my $repo_ref = shift; + my $iorfiles_ref = shift; + + for ($index = 0; $index < $num_srvr; ++$index) { + print "\n\nadding server $index again using tao_imr\n"; + $repo_ref->[$index]->{TI}->Arguments ("-ORBInitRef ImplRepoService" . + "=file://$repo_ref->[$index]->{ti_imriorfile} $refstyle " . + "add $a_srv_name[$index] -c \"$imr_A_SRV_cmd[$index] " . + "-o $iorfiles_ref->[$index] -s $a_srv_name[$index]\" " . + "$repo_ref->[$index]->{server_act_flag} "); + my $TI_status = $repo_ref->[$index]->{TI}->SpawnWaitKill ( + $repo_ref->[$index]->{ti}->ProcessStartWaitInterval()); + if ($TI_status eq 0) { + print STDERR "ERROR: tao_imr ($index) returned $TI_status\n"; + kill_act(); + kill_imr(); + return 1; + } + print "tao_imr returned $TI_status when attempting to add server $index again\n"; } + return 0; +} -#$A_CLI = $a_cli->CreateProcess ("airplane_client", " -k file://$a_cli_airplaneiorfile"); - $A_CLI_status = $A_CLI->SpawnWaitKill ($a_cli->ProcessStartWaitInterval()); - if ($A_CLI_status != 0) { - print STDERR "ERROR: Airplane Client returned $A_CLI_status\n"; - $status = 1; +############################################################################### + +sub remove_servers +{ + my $repo_ref = shift; + + for ($index = 0; $index < $num_srvr; ++$index) { + print "\n\nremoving server $index using tao_imr\n"; + $repo_ref->[$index]->{TI}->Arguments ("-ORBInitRef ImplRepoService" . + "=file://$repo_ref->[$index]->{ti_imriorfile} $refstyle " . + "remove $a_srv_name[$index]"); + my $TI_status = $repo_ref->[$index]->{TI}->SpawnWaitKill ( + $repo_ref->[$index]->{ti}->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr ($index) returned $TI_status\n"; + kill_act(); + kill_imr(); + return 1; + } + print "removed server $index\n"; } + return 0; +} - $A_SRV_status = $A_SRV->TerminateWaitKill ($a_srv->ProcessStopWaitInterval()); - if ($A_SRV_status != 0) { - print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; - $status = 1; +############################################################################### + +sub start_clients +{ + for ($index = 0; $index < $num_srvr; ++$index) { + test_info("starting client for $a_srv_name[$index]=" . + $A_CLI[$index]->CommandLine() . "\n"); + my $A_CLI_status = $A_CLI[$index]->Spawn (); + if ($A_CLI_status != 0) { + print STDERR + "ERROR: Airplane Client ($index) failed to spawn returning $A_CLI_status\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + return 0; +} + +############################################################################### + +sub stop_clients +{ + for ($index = 0; $index < $num_srvr; ++$index) { + my $A_CLI_status = $A_CLI[$index]->WaitKill ($a_cli[$index]->ProcessStartWaitInterval()); + if ($A_CLI_status != 0) { + print STDERR "ERROR: Airplane Client $index returned $A_CLI_status\n"; + return 1; + } + print "\n\nstopped client $index\n\n\n"; + } + return 0; +} + +############################################################################### + +sub shutdown_servers_using_tao_imr +{ + my $repo_ref = shift; + for ($index = 0; $index < $num_srvr; ++$index) { + print "\n\nshutting down server $index using tao_imr\n"; + $repo_ref->[$index]->{TI}->Arguments ("-ORBInitRef ImplRepoService" . + "=file://$repo_ref->[$index]->{ti_imriorfile} $refstyle " . + "shutdown $a_srv_name[$index]"); + my $TI_status = $repo_ref->[$index]->{TI}->SpawnWaitKill ( + $repo_ref->[$index]->{ti}->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr ($index) returned $TI_status\n"; + kill_act(); + kill_imr(); + return 1; + } + print "\n\nshut down server $index using tao_imr\n"; } + return 0; +} + +############################################################################### + +sub wait_for_imr +{ + my $repo_ref = shift; + my $filekey = shift; + + if (!defined($filekey)) { + $filekey = "imriorfile"; + } + my $imr_only = ($filekey eq "imriorfile"); + + if ($repo_ref->{imr}->WaitForFileTimed ( + $repo_ref->{$filekey}, + $repo_ref->{imr}->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <" . + $repo_ref->{"imr_$filekey"} . ">\n"; + kill_imr(); + return 1; + } + if ($repo_ref->{imr}->GetFile ($repo_ref->{$filekey}) == -1) { + print STDERR "ERROR: cannot retrieve file <" . + $repo_ref->{"imr_$filekey"} . ">\n"; + kill_imr(); + return 1; + } + if (!$imr_only) { + if ($repo_ref->{act}->PutFile ($repo_ref->{$filekey}) == -1) { + print STDERR "ERROR: cannot set file <" . + $repo_ref->{"act_$filekey"} . ">\n"; + kill_imr(); + return 1; + } + if ($repo_ref->{ti}->PutFile ($repo_ref->{$filekey}) == -1) { + print STDERR "ERROR: cannot set file <" . + $repo_ref->{"act_$filekey"} . ">\n"; + kill_imr(); + return 1; + } + } + return 0; +} + +############################################################################### + +sub kill_then_timed_wait +{ + my $srvrs = shift; + my $time = shift; + my $length = scalar(@{$srvrs}); + for ($index = 0; $index < $length; ++$index) { + $srvrs->[$index]->Kill (); $srvrs->[$index]->TimedWait (1); + } +} + + +############################################################################### + +sub redirect_output +{ + + my $test_stdout_file = shift; + my $test_stderr_file = shift; + open (OLDOUT, ">&", \*STDOUT) or die "Can't dup STDOUT: $!"; + open (OLDERR, ">&", \*STDERR) or die "Can't dup STDERR: $!"; + open STDOUT, '>', $test_stdout_file; + open STDERR, '>', $test_stderr_file; +} - $a_srv->DeleteFile ($airplaneiorfile); - $a_cli->DeleteFile ($airplaneiorfile); +############################################################################### + +sub restore_output() +{ + open (STDERR, ">&OLDERR") or die "Can't dup OLDERR: $!"; + open (STDOUT, ">&OLDOUT") or die "Can't dup OLDOUT: $!"; +} + + +############################################################################### +# The Tests +############################################################################### + +sub airplane_test +{ + my $status = 0; + my @a_srv_airplaneiorfile; + for ($index = 0; $index < $num_srvr; ++$index) { + push(@a_srv_airplaneiorfile, $a_srv[$index]->LocalFile ($airplaneiorfile[$index])); + $a_srv[$index]->DeleteFile ($airplaneiorfile[$index]); + $a_cli[$index]->DeleteFile ($airplaneiorfile[$index]); + + $A_SRV[$index]->Arguments ( + "-o $a_srv_airplaneiorfile[$index] $refstyle -ORBDebugLevel " . + "$srv_debug_level -s $a_srv_name[$index]"); + my $A_SRV_status = $A_SRV[$index]->Spawn (); + if ($A_SRV_status != 0) { + print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + if ($a_srv[$index]->WaitForFileTimed ($airplaneiorfile[$index],$a_srv[$index]->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$a_srv_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + return 1; + } + if ($a_srv[$index]->GetFile ($airplaneiorfile[$index]) == -1) { + print STDERR "ERROR: cannot retrieve file <$a_srv_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + return 1; + } + if ($a_cli[$index]->PutFile ($airplaneiorfile[$index]) == -1) { + print STDERR "ERROR: cannot set file <$a_cli_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + my $A_CLI_status = $A_CLI[$index]->SpawnWaitKill ($a_cli[$index]->ProcessStartWaitInterval()); + if ($A_CLI_status != 0) { + print STDERR "ERROR: Airplane Client returned $A_CLI_status\n"; + $status = 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + my $A_SRV_status = $A_SRV[$index]->TerminateWaitKill ($a_srv[$index]->ProcessStopWaitInterval()); + if ($A_SRV_status != 0) { + print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; + $status = 1; + } + + $a_srv[$index]->DeleteFile ($airplaneiorfile[$index]); + $a_cli[$index]->DeleteFile ($airplaneiorfile[$index]); + } return $status; } @@ -145,8 +566,9 @@ sub nestea_test $n_srv->DeleteFile ($nesteaiorfile); $n_cli->DeleteFile ($nesteaiorfile); - $N_SRV->Arguments ("-o $n_srv_nesteaiorfile $refstyle -ORBDebugLevel $debug_level"); - $N_SRV_status = $N_SRV->Spawn (); + $N_SRV->Arguments ("-o $n_srv_nesteaiorfile $refstyle -ORBDebugLevel " . + "$srv_debug_level"); + my $N_SRV_status = $N_SRV->Spawn (); if ($N_SRV_status != 0) { print STDERR "ERROR: Nestea Server returned $N_SRV_status\n"; return 1; @@ -167,7 +589,7 @@ sub nestea_test return 1; } - $N_CLI_status = $N_CLI->SpawnWaitKill ($n_cli->ProcessStartWaitInterval()); + my $N_CLI_status = $N_CLI->SpawnWaitKill ($n_cli->ProcessStartWaitInterval()); if ($N_CLI_status != 0) { print STDERR "ERROR: Nestea Client returned $N_CLI_status\n"; $status = 1; @@ -185,23 +607,25 @@ sub nestea_test return $status; } +############################################################################### + sub nt_service_test_i { my ($imr_initref, $BIN_ACT, $BIN_IMR) = @_; - my $a_srv_airplaneiorfile = $a_srv->LocalFile ($airplaneiorfile); + my $a_srv_airplaneiorfile = $a_srv[0]->LocalFile ($airplaneiorfile[0]); print "Installing TAO ImR Services\n"; - $BIN_ACT->Arguments ("-c install $imr_initref -d 0 -ORBDebugLevel $debug_level"); - $BIN_IMR->Arguments ("-c install -d 0 -orbendpoint iiop://:8888"); + $BIN_ACT->Arguments ("-c install $imr_initref -d $test_debug_level -ORBDebugLevel $debug_level"); + $BIN_IMR->Arguments ("-c install -d $test_debug_level -orbendpoint iiop://:8888"); - $BIN_IMR_status = $BIN_IMR->SpawnWaitKill ($bin_imr->ProcessStartWaitInterval()); + my $BIN_IMR_status = $BIN_IMR->SpawnWaitKill ($bin_imr->ProcessStartWaitInterval()); if ($BIN_IMR_status != 0) { print STDERR "ERROR: ImR Service returned $BIN_IMR_status\n"; return 1; } - $BIN_ACT_status = $BIN_ACT->SpawnWaitKill ($bin_act->ProcessStartWaitInterval()); + my $BIN_ACT_status = $BIN_ACT->SpawnWaitKill ($bin_act->ProcessStartWaitInterval()); if ($BIN_ACT_status != 0) { print STDERR "ERROR: ImR Activator returned $BIN_ACT_status\n"; return 1; @@ -214,11 +638,11 @@ sub nt_service_test_i system("net start taoimractivator 2>&1"); # No need to specify imr_initref or -orbuseimr 1 for servers spawned by activator - $TI->Arguments ("$imr_initref add airplane_server -c \"$imr_A_SRV_cmd\" ". + $TI->Arguments ("$imr_initref add $a_srv_name[0] -c \"$imr_A_SRV_cmd[0] -s $a_srv_name[0]\" ". "-w \"$ENV{ACE_ROOT}/lib\""); - $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); + my $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); if ($TI_status != 0) { - print STDERR "ERROR: tao_imr add airplane_server returned $TI_status\n"; + print STDERR "ERROR: tao_imr add $a_srv_name[0] returned $TI_status\n"; return 1; } @@ -229,53 +653,55 @@ sub nt_service_test_i return 1; } - $TI->Arguments ("$imr_initref ior airplane_server -f $a_srv_airplaneiorfile"); + $TI->Arguments ("$imr_initref ior $a_srv_name[0] -f $a_srv_airplaneiorfile"); $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); if ($TI_status != 0) { - print STDERR "ERROR: tao_imr ior airplane_server returned $TI_status\n"; + print STDERR "ERROR: tao_imr ior $a_srv_name[0] returned $TI_status\n"; return 1; } - if ($a_srv->WaitForFileTimed ($airplaneiorfile,$a_srv->ProcessStartWaitInterval()) == -1) { + if ($a_srv[0]->WaitForFileTimed ($airplaneiorfile[0],$a_srv[0]->ProcessStartWaitInterval()) == -1) { print STDERR "ERROR: cannot find file <$a_srv_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + kill_then_timed_wait(\@A_SRV, 1); return 1; } - if ($a_srv->GetFile ($airplaneiorfile) == -1) { + if ($a_srv[0]->GetFile ($airplaneiorfile[0]) == -1) { print STDERR "ERROR: cannot retrieve file <$a_srv_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + kill_then_timed_wait(\@A_SRV, 1); return 1; } - if ($a_cli->PutFile ($airplaneiorfile) == -1) { - print STDERR "ERROR: cannot set file <$a_cli_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + if ($a_cli[0]->PutFile ($airplaneiorfile[0]) == -1) { + print STDERR "ERROR: cannot set file <$a_cli_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); return 1; } - $A_CLI_status = $A_CLI->SpawnWaitKill ($a_cli->ProcessStartWaitInterval()+5); + my $A_CLI_status = $A_CLI[0]->SpawnWaitKill ($a_cli[0]->ProcessStartWaitInterval()+5); if ($A_CLI_status != 0) { print STDERR "ERROR: airplane client returned $A_CLI_status\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + kill_then_timed_wait(\@A_SRV, 1); return 1; } - $TI->Arguments ("$imr_initref shutdown airplane_server"); + $TI->Arguments ("$imr_initref shutdown $a_srv_name[0]"); $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()+5); if ($TI_status != 0) { - print STDERR "ERROR: tao_imr shutdown airplane_server returned $TI_status\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + print STDERR "ERROR: tao_imr shutdown $a_srv_name[0] returned $TI_status\n"; + kill_then_timed_wait(\@A_SRV, 1); return 1; } return 0; } +############################################################################### + sub nt_service_test { my $result = 0; - my $a_srv_airplaneiorfile = $a_srv->LocalFile ($airplaneiorfile); - $a_srv->DeleteFile ($airplaneiorfile); - $a_cli->DeleteFile ($airplaneiorfile); + my $a_srv_airplaneiorfile = $a_srv[0]->LocalFile ($airplaneiorfile[0]); + $a_srv[0]->DeleteFile ($airplaneiorfile[0]); + $a_cli[0]->DeleteFile ($airplaneiorfile[0]); my $bin_imr_host = $bin_imr->HostName (); @@ -304,11 +730,11 @@ sub nt_service_test print "Removing any existing TAO ImR Services\n"; $BIN_ACT->Arguments ("-c remove"); $BIN_IMR->Arguments ("-c remove"); - $BIN_ACT_status = $BIN_ACT->SpawnWaitKill ($bin_act->ProcessStartWaitInterval()); + my $BIN_ACT_status = $BIN_ACT->SpawnWaitKill ($bin_act->ProcessStartWaitInterval()); if ($BIN_ACT_status < 0) { print STDERR "ERROR: BIN Activator returned $BIN_ACT_status\n"; } - $BIN_IMR_status = $BIN_IMR->SpawnWaitKill ($bin_imr->ProcessStartWaitInterval()); + my $BIN_IMR_status = $BIN_IMR->SpawnWaitKill ($bin_imr->ProcessStartWaitInterval()); if ($BIN_IMR_status < 0) { print STDERR "ERROR: BIN ImR Service returned $BIN_IMR_status\n"; } @@ -335,8 +761,8 @@ sub nt_service_test $bin_imr->DeleteFile ($BIN_IMR->Executable ()); $bin_act->DeleteFile ($BIN_ACT->Executable ()); - $a_srv->DeleteFile ($airplaneiorfile); - $a_cli->DeleteFile ($airplaneiorfile); + $a_srv[0]->DeleteFile ($airplaneiorfile[0]); + $a_cli[0]->DeleteFile ($airplaneiorfile[0]); return $result; } @@ -347,163 +773,293 @@ sub airplane_ir_test { my $status = 0; - my $imr_imriorfile = $imr->LocalFile ($imriorfile); - my $act_imriorfile = $act->LocalFile ($imriorfile); - my $ti_imriorfile = $ti->LocalFile ($imriorfile); - my $a_srv_imriorfile = $a_srv->LocalFile ($imriorfile); - my $act_actiorfile = $act->LocalFile ($actiorfile); - my $imr_airplaneiorfile = $imr->LocalFile ($airplaneiorfile); - my $a_srv_airplaneiorfile = $a_srv->LocalFile ($airplaneiorfile); + if ($srv_debug_level < 2 && $replica) { + $srv_debug_level = 2;#"2 -ORBLogFile server.log"; + } + + my $imr_port = 10001 + $imr->RandomPort (); + print "\n\nimr_port=$imr_port\n"; + my %repo; + setup_repo(\%repo, $imr, $IMR, $imriorfile, $act, $ACT, $actiorfile, $ti, + $TI, $imr_port, "--primary", $backupiorfile); + + my %backup_repo; + if ($replica) { + setup_repo(\%backup_repo, $replica_imr, $replica_IMR, + $replica_imriorfile, $act, $ACT, $actiorfile, + $ti, $TI, $imr_port + 1, "--backup", + $primaryiorfile); + } + + my @repo_for_srvr; + my @a_srv_imriorfile; + my @imr_airplaneiorfile; + my @a_srv_airplaneiorfile; + for ($index = 0; $index < $num_srvr; ++$index) { + if ($index == ($num_srvr - 1) && $replica) { + push(@repo_for_srvr, \%backup_repo); + } + else { + push(@repo_for_srvr, \%repo); + } + + push(@a_srv_imriorfile, $a_srv[$index]->LocalFile ($repo_for_srvr[$index]->{imriorfile})); + push(@imr_airplaneiorfile, $repo_for_srvr[$index]->{imr}->LocalFile ($airplaneiorfile[$index])); + push(@a_srv_airplaneiorfile, $a_srv[$index]->LocalFile ($airplaneiorfile[$index])); + $a_srv[$index]->DeleteFile ($repo_for_srvr[$index]->{imriorfile}); + $a_srv[$index]->DeleteFile ($airplaneiorfile[$index]); + $a_cli[$index]->DeleteFile ($airplaneiorfile[$index]); + $repo_for_srvr[$index]->{imr}->DeleteFile ($airplaneiorfile[$index]); + } $imr->DeleteFile ($imriorfile); $act->DeleteFile ($imriorfile); $ti->DeleteFile ($imriorfile); - $a_srv->DeleteFile ($imriorfile); $act->DeleteFile ($actiorfile); - $imr->DeleteFile ($airplaneiorfile); - $a_srv->DeleteFile ($airplaneiorfile); - $a_cli->DeleteFile ($airplaneiorfile); + if ($replica) { + $replica_imr->DeleteFile ($replica_imriorfile); + cleanup_replication($repo{imr_backing_store}); + } - $IMR->Arguments ("-d 2 -o $imr_imriorfile $refstyle"); - $IMR_status = $IMR->Spawn (); + print "\n\nstarting IMR\n"; + $repo{IMR}->Arguments ("-d $test_debug_level -o $repo{imr_imriorfile} " . + "$imr_refstyle $repo{imr_backing_store_flag} $repo{imr_endpoint_flag}"); + my $IMR_status = $repo{IMR}->Spawn (); if ($IMR_status != 0) { print STDERR "ERROR: ImR Service returned $IMR_status\n"; return 1; } - if ($imr->WaitForFileTimed ($imriorfile,$imr->ProcessStartWaitInterval()) == -1) { - print STDERR "ERROR: cannot find file <$imr_imriorfile>\n"; - $IMR->Kill (); $IMR->TimedWait (1); - return 1; - } - if ($imr->GetFile ($imriorfile) == -1) { - print STDERR "ERROR: cannot retrieve file <$imr_imriorfile>\n"; - $IMR->Kill (); $IMR->TimedWait (1); - return 1; - } - if ($act->PutFile ($imriorfile) == -1) { - print STDERR "ERROR: cannot set file <$act_imriorfile>\n"; - $IMR->Kill (); $IMR->TimedWait (1); - return 1; - } - if ($ti->PutFile ($imriorfile) == -1) { - print STDERR "ERROR: cannot set file <$ti_imriorfile>\n"; - $IMR->Kill (); $IMR->TimedWait (1); - return 1; - } - if ($a_srv->PutFile ($imriorfile) == -1) { - print STDERR "ERROR: cannot set file <$a_srv_imriorfile>\n"; - $IMR->Kill (); $IMR->TimedWait (1); - return 1; - } - - $ACT->Arguments ("-d 2 -o $act_actiorfile -ORBInitRef ImplRepoService=file://$act_imriorfile"); - $ACT_status = $ACT->Spawn (); + if ($replica) { + if (wait_for_imr(\%backup_repo, "replicaiorfile")) { + return 1; + } + print "\n\nstarting backup IMR\n"; + $backup_repo{IMR}->Arguments ("-d $test_debug_level -o " . + "$backup_repo{imr_imriorfile} $imr_refstyle " . + "$backup_repo{imr_backing_store_flag} " . + "$backup_repo{imr_endpoint_flag}"); + my $replica_IMR_status = $backup_repo{IMR}->Spawn (); + if ($replica_IMR_status != 0) { + print STDERR "ERROR: ImR Service replica returned $replica_IMR_status\n"; + return 1; + } + if (wait_for_imr(\%repo, "replicaiorfile")) { + return 1; + } + print "started backup IMR\n"; + } + if (wait_for_imr(\%repo)) { + return 1; + } + print "started IMR\n"; + + for ($index = 0; $index < $num_srvr; ++$index) { + if ($a_srv[$index]->PutFile ($repo_for_srvr[$index]->{imriorfile}) == -1) { + print STDERR "ERROR: cannot set file <$a_srv_imriorfile[$index]>\n"; + kill_imr(); + return 1; + } + } + + print "\n\nstarting ACT\n"; + $repo{ACT}->Arguments ("-d $test_debug_level -o $repo{act_actiorfile} " . + "-ORBInitRef ImplRepoService=file://$repo{act_imriorfile} $refstyle " . + $repo{act_explicit_flag}); + my $ACT_status = $repo{ACT}->Spawn (); if ($ACT_status != 0) { print STDERR "ERROR: ImR Activator returned $ACT_status\n"; return 1; } - if ($act->WaitForFileTimed ($actiorfile,$act->ProcessStartWaitInterval()) == -1) { - print STDERR "ERROR: cannot find file <$act_actiorfile>\n"; - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); + + if ($repo{act}->WaitForFileTimed ( + $repo{actiorfile}, + $repo{act}->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <" . + $repo{act_actiorfile} . ">\n"; + kill_act(); + kill_imr(); return 1; } + print "started ACT\n"; # No need to specify imr_initref or -orbuseimr 1 for servers spawned by activator # Can use update to add servers. - $TI->Arguments ("-ORBInitRef ImplRepoService=file://$ti_imriorfile ". - "update airplane_server -c \"$imr_A_SRV_cmd -o $imr_airplaneiorfile\""); - $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); - if ($TI_status != 0) { - print STDERR "ERROR: tao_imr returned $TI_status\n"; - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); - return 1; - } - - $A_SRV->Arguments ("-ORBUseIMR 1 -o $a_srv_airplaneiorfile ". - "-ORBInitRef ImplRepoService=file://$a_srv_imriorfile ". - "-ORBDebugLevel $debug_level"); - $A_SRV_status = $A_SRV->Spawn (); - if ($A_SRV_status != 0) { - print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; - return 1; - } - if ($a_srv->WaitForFileTimed ($airplaneiorfile,$a_srv->ProcessStartWaitInterval()) == -1) { - print STDERR "ERROR: cannot find file <$a_srv_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); - return 1; - } - if ($a_srv->GetFile ($airplaneiorfile) == -1) { - print STDERR "ERROR: cannot retrieve file <$a_srv_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); - return 1; - } - if ($a_cli->PutFile ($airplaneiorfile) == -1) { - print STDERR "ERROR: cannot set file <$a_cli_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); - return 1; - } - - $A_CLI_status = $A_CLI->SpawnWaitKill ($a_cli->ProcessStartWaitInterval()); - if ($A_CLI_status != 0) { - print STDERR "ERROR: Airplane Client 1 returned $A_CLI_status\n"; - $status = 1; - } - - $TI->Arguments ("-ORBInitRef ImplRepoService=file://$ti_imriorfile shutdown airplane_server"); - - $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); - if ($TI_status != 0) { - print STDERR "ERROR: tao_imr 1 returned $TI_status\n"; - $status = 1; - } - - # This client should force a new airplane_server to be started - $A_CLI_status = $A_CLI->SpawnWaitKill ($a_cli->ProcessStartWaitInterval()); - if ($A_CLI_status != 0) { - print STDERR "ERROR: Airplane Client 2 returned $A_CLI_status\n"; - $status = 1; - } - - $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); - if ($TI_status != 0) { - print STDERR "ERROR: tao_imr 2 returned $TI_status\n"; - $status = 1; - } - - $A_SRV_status = $A_SRV->WaitKill ($a_srv->ProcessStopWaitInterval()); - if ($A_SRV_status != 0) { - print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; - $status = 1; - } - - $ACT_status = $ACT->TerminateWaitKill ($act->ProcessStopWaitInterval()); + for ($index = 0; $index < $num_srvr; ++$index) { + print "\n\nstarting TI $index\n"; + $repo_for_srvr[$index]->{TI}->Arguments ("-ORBInitRef ImplRepoService" . + "=file://$repo_for_srvr[$index]->{ti_imriorfile} $refstyle " . + "update $a_srv_name[$index] -c \"$imr_A_SRV_cmd[$index] " . + "-o $imr_airplaneiorfile[$index] -s $a_srv_name[$index]\" " . + "$repo_for_srvr[$index]->{server_act_flag} "); + my $TI_status = $repo_for_srvr[$index]->{TI}->SpawnWaitKill ( + $repo_for_srvr[$index]->{ti}->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr ($index) returned $TI_status\n"; + kill_act(); + kill_imr(); + return 1; + } + print "stopped TI $index\n"; + + print "\n\nstarting srv $index\n"; + $A_SRV[$index]->Arguments ( + "-ORBUseIMR 1 -o $a_srv_airplaneiorfile[$index] $refstyle ". + "-ORBInitRef ImplRepoService=file://$a_srv_imriorfile[$index] ". + "-ORBDebugLevel $srv_debug_level -s $a_srv_name[$index] "); + my $A_SRV_status = $A_SRV[$index]->Spawn (); + if ($A_SRV_status != 0) { + print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + if ($a_srv[$index]->WaitForFileTimed ($airplaneiorfile[$index],$a_srv[$index]->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$a_srv_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + kill_act(); + kill_imr(); + return 1; + } + if ($a_srv[$index]->GetFile ($airplaneiorfile[$index]) == -1) { + print STDERR "ERROR: cannot retrieve file <$a_srv_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + kill_act(); + kill_imr(); + return 1; + } + if ($a_cli[$index]->PutFile ($airplaneiorfile[$index]) == -1) { + print STDERR "ERROR: cannot set file <$a_cli_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + kill_act(); + kill_imr(); + return 1; + } + print "\n\nstarted srv $index\n\n"; + } + + for ($index = 0; $index < $num_srvr; ++$index) { + print "\n\nstarting client $index\n"; + my $A_CLI_status = $A_CLI[$index]->Spawn (); + if ($A_CLI_status != 0) { + print STDERR "ERROR: Airplane Client $index failed to spawn returning $A_CLI_status\n"; + $status = 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + my $A_CLI_status = $A_CLI[$index]->WaitKill ($a_cli[$index]->ProcessStartWaitInterval()); + if ($A_CLI_status != 0) { + print STDERR "ERROR: Airplane Client $index returned $A_CLI_status\n"; + $status = 1; + } + print "\n\nstopped client $index\n\n\n"; + } + + for ($index = 0; $index < $num_srvr; ++$index) { + print "\n\nstarting TI $index (2)\n"; + $repo_for_srvr[$index]->{TI}->Arguments ("-ORBInitRef " . + "ImplRepoService=file://$repo_for_srvr[$index]->{ti_imriorfile} " . + "$refstyle shutdown $a_srv_name[$index]"); + + my $TI_status = $repo_for_srvr[$index]->{TI}->SpawnWaitKill ( + $repo_for_srvr[$index]->{ti}->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr 1 ($index) returned $TI_status\n"; + $status = 1; + } + print "stopped TI $index (2)\n"; + } + + for ($index = 0; $index < $num_srvr; ++$index) { + print "\n\nstarting client $index\n"; + # This client should force a new airplane_server to be started + my $A_CLI_status = $A_CLI[$index]->SpawnWaitKill ( + $a_cli[$index]->ProcessStartWaitInterval()); + if ($A_CLI_status != 0) { + print STDERR "ERROR: restarted Airplane Client $index returned " . + "$A_CLI_status\n"; + $status = 1; + } + print "stopped client $index\n"; + + print "\n\nstarting client $index\n"; + $repo_for_srvr[$index]->{TI}->Arguments ("-ORBInitRef " . + "ImplRepoService=file://$repo_for_srvr[$index]->{ti_imriorfile} " . + "$refstyle shutdown $a_srv_name[$index]"); + + my $TI_status = $repo_for_srvr[$index]->{TI}->SpawnWaitKill ( + $repo_for_srvr[$index]->{ti}->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr 2 ($index) returned $TI_status\n"; + $status = 1; + } + print "stopped client $index\n"; + } + + for ($index = 0; $index < $num_srvr; ++$index) { + print "\n\nkilling srv $index\n"; + my $A_SRV_status = $A_SRV[$index]->WaitKill ($a_srv[$index]->ProcessStopWaitInterval()); + if ($A_SRV_status != 0) { + print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; + $status = 1; + } + print "stopped srv $index\n"; + } + + print "\n\nkilling ACT\n"; + $ACT_status = $repo{ACT}->TerminateWaitKill ( + $repo{act}->ProcessStopWaitInterval()); if ($ACT_status != 0) { print STDERR "ERROR: Activator returned $ACT_status\n"; $status = 1; } + print "stopped ACT\n"; - $IMR_status = $IMR->TerminateWaitKill ($imr->ProcessStopWaitInterval()); + print "\n\nkilling IMR\n"; + $IMR_status = $repo{IMR}->TerminateWaitKill ( + $repo{imr}->ProcessStopWaitInterval()); if ($IMR_status != 0) { print STDERR "ERROR: ImR returned $IMR_status\n"; $status = 1; } - - $imr->DeleteFile ($imriorfile); - $act->DeleteFile ($imriorfile); - $ti->DeleteFile ($imriorfile); - $a_srv->DeleteFile ($imriorfile); - $act->DeleteFile ($actiorfile); - $imr->DeleteFile ($airplaneiorfile); - $a_srv->DeleteFile ($airplaneiorfile); - $a_cli->DeleteFile ($airplaneiorfile); - + print "stopped IMR\n"; + + if ($replica) { + print "\n\nkilling backup IMR\n"; + $IMR_status = $backup_repo{IMR}->TerminateWaitKill ( + $backup_repo{imr}->ProcessStopWaitInterval()); + if ($IMR_status != 0) { + print STDERR "ERROR: replica ImR returned $IMR_status\n"; + $status = 1; + } + print "stopped backup IMR\n"; + } + + $repo{imr}->DeleteFile ($repo{imriorfile}); + $repo{act}->DeleteFile ($repo{imriorfile}); + $repo{ti}->DeleteFile ($repo{imriorfile}); + $repo{act}->DeleteFile ($repo{actiorfile}); + + if ($replica) { + $backup_repo{imr}->DeleteFile ( + $backup_repo{imriorfile}); + $backup_repo{act}->DeleteFile ( + $backup_repo{imriorfile}); + $backup_repo{ti}->DeleteFile ( + $backup_repo{imriorfile}); + $backup_repo{act}->DeleteFile ( + $backup_repo{actiorfile}); + cleanup_replication($repo{imr_backing_store}); + } + + for ($index = 0; $index < $num_srvr; ++$index) { + $repo_for_srvr[$index]->{imr}->DeleteFile ( + $airplaneiorfile[$index]); + $a_srv[$index]->DeleteFile ( + $repo_for_srvr[$index]->{imriorfile}); + $a_srv[$index]->DeleteFile ($airplaneiorfile[$index]); + $a_cli[$index]->DeleteFile ($airplaneiorfile[$index]); + } return $status; } @@ -529,13 +1085,14 @@ sub nestea_ir_test $n_srv->DeleteFile ($nesteaiorfile); $n_cli->DeleteFile ($nesteaiorfile); - $IMR->Arguments ("-d 2 -o $imr_imriorfile $refstyle"); - $IMR_status = $IMR->Spawn (); + $IMR->Arguments ("-d $test_debug_level -o $imr_imriorfile $imr_refstyle"); + my $IMR_status = $IMR->Spawn (); if ($IMR_status != 0) { print STDERR "ERROR: ImR Service returned $IMR_status\n"; return 1; } - if ($imr->WaitForFileTimed ($imriorfile,$imr->ProcessStartWaitInterval()) == -1) { + if ($imr->WaitForFileTimed ($imriorfile, + $imr->ProcessStartWaitInterval()) == -1) { print STDERR "ERROR: cannot find file <$imr_imriorfile>\n"; $IMR->Kill (); $IMR->TimedWait (1); return 1; @@ -561,9 +1118,10 @@ sub nestea_ir_test return 1; } - $ACT->Arguments ("-d 2 -o $act_actiorfile ". - "-orbobjrefstyle URL -ORBInitRef ImplRepoService=file://$act_imriorfile"); - $ACT_status = $ACT->Spawn (); + $ACT->Arguments ( + "-d $test_debug_level -o $act_actiorfile -orbobjrefstyle URL ". + "-ORBInitRef ImplRepoService=file://$act_imriorfile"); + my $ACT_status = $ACT->Spawn (); if ($ACT_status != 0) { print STDERR "ERROR: ImR Activator returned $ACT_status\n"; return 1; @@ -575,10 +1133,11 @@ sub nestea_ir_test return 1; } - $N_SRV->Arguments ("-ORBUseIMR 1 -o $n_srv_nesteaiorfile ". - "-orbobjrefstyle URL -ORBInitRef ImplRepoService=file://$n_srv_imriorfile ". - "-ORBDebugLevel $debug_level"); - $N_SRV_status = $N_SRV->Spawn (); + $N_SRV->Arguments ( + "-ORBUseIMR 1 -o $n_srv_nesteaiorfile -orbobjrefstyle URL ". + "-ORBInitRef ImplRepoService=file://$n_srv_imriorfile ". + "-ORBDebugLevel $srv_debug_level"); + my $N_SRV_status = $N_SRV->Spawn (); if ($N_SRV_status != 0) { print STDERR "ERROR: Nestea Server returned $N_SRV_status\n"; return 1; @@ -605,7 +1164,7 @@ sub nestea_ir_test return 1; } - $N_CLI_status = $N_CLI->SpawnWaitKill ($n_cli->ProcessStartWaitInterval()); + my $N_CLI_status = $N_CLI->SpawnWaitKill ($n_cli->ProcessStartWaitInterval()); if ($N_CLI_status != 0) { print STDERR "ERROR: Nestea Client 1 returned $N_CLI_status\n"; $N_SRV->Kill (); $N_SRV->TimedWait (1); @@ -617,7 +1176,7 @@ sub nestea_ir_test $TI->Arguments ("-orbobjrefstyle URL -ORBInitRef ImplRepoService=file://$ti_imriorfile ". " shutdown nestea_server"); - $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); + my $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); if ($TI_status != 0) { print STDERR "ERROR: tao_imr 1 returned $TI_status\n"; $N_SRV->Kill (); $N_SRV->TimedWait (1); @@ -741,14 +1300,16 @@ sub perclient my $imr_host = $imr->HostName (); # specify an endpoint so that we can use corbaloc url for the client. - $IMR->Arguments ("-d 2 -orbendpoint iiop://:8888 -o $imr_imriorfile $refstyle ". - "-ORBDebugLevel $debug_level"); - $IMR_status = $IMR->Spawn (); + $IMR->Arguments ( + "-d $test_debug_level -orbendpoint iiop://:8888 ". + "-o $imr_imriorfile $imr_refstyle -ORBDebugLevel $debug_level"); + my $IMR_status = $IMR->Spawn (); if ($IMR_status != 0) { print STDERR "ERROR: ImR Service returned $IMR_status\n"; return 1; } - if ($imr->WaitForFileTimed ($imriorfile,$imr->ProcessStartWaitInterval()) == -1) { + if ($imr->WaitForFileTimed ($imriorfile, + $imr->ProcessStartWaitInterval()) == -1) { print STDERR "ERROR: cannot find file <$imr_imriorfile>\n"; $IMR->Kill (); $IMR->TimedWait (1); return 1; @@ -769,9 +1330,9 @@ sub perclient return 1; } - $ACT->Arguments ("-d 2 -o $act_actiorfile ". + $ACT->Arguments ("-d $test_debug_level -o $act_actiorfile ". "-orbobjrefstyle URL -ORBInitRef ImplRepoService=file://$act_imriorfile"); - $ACT_status = $ACT->Spawn (); + my $ACT_status = $ACT->Spawn (); if ($ACT_status != 0) { print STDERR "ERROR: ImR Activator returned $ACT_status\n"; return 1; @@ -787,7 +1348,7 @@ sub perclient $TI->Arguments ("-orbobjrefstyle URL -ORBInitRef ImplRepoService=file://$ti_imriorfile ". "add nestea_server -a PER_CLIENT ". "-c \"$imr_N_SRV_cmd -o $imr_nesteaiorfile\""); - $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); + my $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); if ($TI_status != 0) { print STDERR "ERROR: tao_imr returned $TI_status\n"; $ACT->Kill (); $ACT->TimedWait (1); @@ -798,21 +1359,21 @@ sub perclient $N_CLI->Arguments("-k corbaloc::$imr_host:8888/nestea_server"); # Running the client should start a server instance - $N_CLI_status = $N_CLI->SpawnWaitKill ($n_cli->ProcessStartWaitInterval()+5); + my $N_CLI_status = $N_CLI->SpawnWaitKill ($n_cli->ProcessStartWaitInterval()+5); if ($N_CLI_status != 0) { print STDERR "ERROR: Nestea Client 1 returned $N_CLI_status\n"; $ACT->Kill (); $ACT->TimedWait (1); $IMR->Kill (); $IMR->TimedWait (1); return 1; } - if ($n_cli->WaitForFileTimed ($nesteaiorfile,$a_cli->ProcessStartWaitInterval()) == -1) { - print STDERR "ERROR: cannot find file <$a_cli_nesteaiorfile>\n"; + if ($n_cli->WaitForFileTimed ($nesteaiorfile,$a_cli[0]->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$n_cli_nesteaiorfile>\n"; $ACT->Kill (); $ACT->TimedWait (1); $IMR->Kill (); $IMR->TimedWait (1); return 1; } - $a_cli->DeleteFile ($nesteaiorfile); + $a_cli[0]->DeleteFile ($nesteaiorfile); $N_CLI->Arguments("-s -k corbaloc::$imr_host:8888/nestea_server"); @@ -824,8 +1385,8 @@ sub perclient $IMR->Kill (); $IMR->TimedWait (1); return 1; } - if ($n_cli->WaitForFileTimed ($nesteaiorfile,$a_cli->ProcessStartWaitInterval()) == -1) { - print STDERR "ERROR: cannot find file <$a_cli_nesteaiorfile>\n"; + if ($n_cli->WaitForFileTimed ($nesteaiorfile,$a_cli[0]->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$n_cli_nesteaiorfile>\n"; $ACT->Kill (); $ACT->TimedWait (1); $IMR->Kill (); $IMR->TimedWait (1); return 1; @@ -856,7 +1417,6 @@ sub perclient return $status; } - ############################################################################### sub shutdown_repo @@ -878,14 +1438,15 @@ sub shutdown_repo # Specify an endpoint so that we can restart on the same port. # Specify persistence so that we can test that shutdown-repo -a works after reconnect - $IMR->Arguments ("-p $imr_testrepo -d 1 -orbendpoint iiop://:8888 -o $imr_imriorfile $refstyle ". + $IMR->Arguments ("-p $imr_testrepo -d 1 -orbendpoint iiop://:8888 -o $imr_imriorfile $imr_refstyle ". "-ORBDebugLevel $debug_level"); - $IMR_status = $IMR->Spawn (); + my $IMR_status = $IMR->Spawn (); if ($IMR_status != 0) { print STDERR "ERROR: ImR Service returned $IMR_status\n"; return 1; } - if ($imr->WaitForFileTimed ($imriorfile,$imr->ProcessStartWaitInterval()) == -1) { + if ($imr->WaitForFileTimed ($imriorfile, + $imr->ProcessStartWaitInterval()) == -1) { print STDERR "ERROR: cannot find file <$imr_imriorfile>\n"; $IMR->Kill (); $IMR->TimedWait (1); return 1; @@ -908,7 +1469,7 @@ sub shutdown_repo $ACT->Arguments ("-d 1 -o $act_actiorfile ". "-orbobjrefstyle URL -ORBInitRef ImplRepoService=file://$act_imriorfile"); - $ACT_status = $ACT->Spawn (); + my $ACT_status = $ACT->Spawn (); if ($ACT_status != 0) { print STDERR "ERROR: ImR Activator returned $ACT_status\n"; return 1; @@ -923,7 +1484,7 @@ sub shutdown_repo # Kill the ImR, but leave the activator running $TI->Arguments ("-orbobjrefstyle URL -ORBInitRef ImplRepoService=file://$ti_imriorfile ". "shutdown-repo"); - $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); + my $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); if ($TI_status != 0) { print STDERR "ERROR: tao_imr returned $TI_status\n"; $ACT->Kill (); $ACT->TimedWait (1); @@ -944,7 +1505,8 @@ sub shutdown_repo print STDERR "ERROR: ImR Service returned $IMR_status\n"; return 1; } - if ($imr->WaitForFileTimed ($imriorfile,$imr->ProcessStartWaitInterval()) == -1) { + if ($imr->WaitForFileTimed ($imriorfile, + $imr->ProcessStartWaitInterval()) == -1) { print STDERR "ERROR: cannot find file <$imr_imriorfile>\n"; $IMR->Kill (); $IMR->TimedWait (1); return 1; @@ -993,35 +1555,65 @@ sub shutdown_repo sub persistent_ir_test { + my $backing_store_flag = shift; my $status = 0; + if ($srv_debug_level == 0) { + $srv_debug_level = 1; + } + + test_info("persistent_ir_test start\n"); + + my $backing_store; + if ($backing_store_flag eq "-p") { + $backing_store = "test.repo"; + } elsif ($backing_store_flag eq "--directory") { + $backing_store = "."; + } elsif ($backing_store_flag eq "-x") { + $backing_store = "imr_backing_store.xml"; + } + my $imr_imriorfile = $imr->LocalFile ($imriorfile); - my $imr_storefile = $imr->LocalFile ($backing_store); + my $imr_storefile; + if (defined($backing_store)) { + $imr_storefile = $imr->LocalFile ($backing_store); + } my $act_imriorfile = $act->LocalFile ($imriorfile); my $ti_imriorfile = $ti->LocalFile ($imriorfile); - my $a_srv_imriorfile = $a_srv->LocalFile ($imriorfile); my $act_actiorfile = $act->LocalFile ($actiorfile); - my $imr_airplaneiorfile = $imr->LocalFile ($airplaneiorfile); - my $a_srv_airplaneiorfile = $a_srv->LocalFile ($airplaneiorfile); + + my @a_srv_imriorfile; + my @imr_airplaneiorfile; + my @a_srv_airplaneiorfile; + for ($index = 0; $index < $num_srvr; ++$index) { + push(@a_srv_imriorfile, $a_srv[$index]->LocalFile ($imriorfile)); + push(@imr_airplaneiorfile, $imr->LocalFile ($airplaneiorfile[$index])); + push(@a_srv_airplaneiorfile, $a_srv[$index]->LocalFile ($airplaneiorfile[$index])); + $a_srv[$index]->DeleteFile ($imriorfile); + $a_srv[$index]->DeleteFile ($airplaneiorfile[$index]); + $a_cli[$index]->DeleteFile ($airplaneiorfile[$index]); + $imr->DeleteFile ($airplaneiorfile[$index]); + } $imr->DeleteFile ($imriorfile); - $imr->DeleteFile ($backing_store); + if ($backing_store_flag eq "--directory") { + cleanup_replication($imr_storefile); + } $act->DeleteFile ($imriorfile); $ti->DeleteFile ($imriorfile); - $a_srv->DeleteFile ($imriorfile); $act->DeleteFile ($actiorfile); - $imr->DeleteFile ($airplaneiorfile); - $a_srv->DeleteFile ($airplaneiorfile); - $a_cli->DeleteFile ($airplaneiorfile); ## Be sure to start the ImR on a consistent endpoint, so that any created IORs ## remain valid even if the ImR restarts. - $IMR->Arguments ("-orbendpoint iiop://:8888 -x $imr_storefile -d 2 -o $imr_imriorfile $refstyle"); - $IMR_status = $IMR->Spawn (); + my $imr_arguments = "-orbendpoint iiop://:8888 $backing_store_flag $imr_storefile -d $test_debug_level -o $imr_imriorfile $imr_refstyle "; + $IMR->Arguments ("$imr_arguments -e "); + test_info("starting IMR=" . $IMR->CommandLine() . "\n"); + my $IMR_status = $IMR->Spawn (); if ($IMR_status != 0) { print STDERR "ERROR: ImR Service returned $IMR_status\n"; return 1; } - if ($imr->WaitForFileTimed ($imriorfile,$imr->ProcessStartWaitInterval()) == -1) { + if ($imr->WaitForFileTimed ($imriorfile, + $imr->ProcessStartWaitInterval()) == -1) { print STDERR "ERROR: cannot find file <$imr_imriorfile>\n"; $IMR->Kill (); $IMR->TimedWait (1); return 1; @@ -1041,18 +1633,23 @@ sub persistent_ir_test $IMR->Kill (); $IMR->TimedWait (1); return 1; } - if ($a_srv->PutFile ($imriorfile) == -1) { - print STDERR "ERROR: cannot set file <$a_srv_imriorfile>\n"; - $IMR->Kill (); $IMR->TimedWait (1); - return 1; + + for ($index = 0; $index < $num_srvr; ++$index) { + if ($a_srv[$index]->PutFile ($imriorfile) == -1) { + print STDERR "ERROR: cannot set file <$a_srv_imriorfile[$index]>\n"; + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } } - $ACT->Arguments ("-d 2 -o $act_actiorfile -ORBInitRef ImplRepoService=file://$act_imriorfile"); - $ACT_status = $ACT->Spawn (); + $ACT->Arguments ("-d $test_debug_level -o $act_actiorfile -ORBInitRef ImplRepoService=file://$act_imriorfile"); + test_info("starting ACT=" . $ACT->CommandLine() . "\n"); + my $ACT_status = $ACT->Spawn (); if ($ACT_status != 0) { print STDERR "ERROR: ImR Activator returned $ACT_status\n"; return 1; } + if ($act->WaitForFileTimed ($actiorfile,$act->ProcessStartWaitInterval()) == -1) { print STDERR "ERROR: cannot find file <$act_actiorfile>\n"; $ACT->Kill (); $ACT->TimedWait (1); @@ -1066,190 +1663,923 @@ sub persistent_ir_test return 1; } - $p_srv->DeleteFile ($P_SRV_cmd); - # Copy the server to a path with spaces to ensure that these - # work corrrectly. - copy ($A_SRV_cmd, $P_SRV_cmd); - chmod(0755, $P_SRV_cmd); + for ($index = 0; $index < $num_srvr; ++$index) { + $p_srv[$index]->DeleteFile ($P_SRV_cmd[$index]); + # Copy the server to a path with spaces to ensure that these + # work corrrectly. + copy ($A_SRV_cmd[$index], $P_SRV_cmd[$index]); + chmod(0755, $P_SRV_cmd[$index]); + } + + for ($index = 0; $index < $num_srvr; ++$index) { + # No need to specify imr_initref or -orbuseimr 1 for servers spawned by activator + $TI->Arguments ( + "-ORBInitRef ImplRepoService=file://$ti_imriorfile ". + "add $a_srv_name[$index] -c \"\\\"$imr_P_SRV_cmd[$index]\\\" " . + "$refstyle -s $a_srv_name[$index]\""); + test_info("starting TI=" . $TI->CommandLine() . "\n"); + my $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr ($index) returned $TI_status\n"; + $p_srv[$index]->DeleteFile ($P_SRV_cmd[$index]); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + ## This will write out the imr-ified IOR. Note : If you don't use -orbendpoint + ## when starting the ImR, then this IOR will no longer be valid when the ImR + ## restarts below. You can fix this by creating a new valid IOR, or starting + ## the ImR on a consistent endpoint. + $A_SRV[$index]->Arguments ( + "-o $a_srv_airplaneiorfile[$index] -ORBUseIMR 1 $refstyle ". + "-ORBInitRef ImplRepoService=file://$a_srv_imriorfile[$index] ". + "-ORBDebugLevel $srv_debug_level -s $a_srv_name[$index]"); + test_info("starting $a_srv_name[$index]=" . + $A_SRV[$index]->CommandLine() . "\n"); + my $A_SRV_status = $A_SRV[$index]->Spawn (); + if ($A_SRV_status != 0) { + print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + if ($a_srv[$index]->WaitForFileTimed ( + $airplaneiorfile[$index], + $a_srv[$index]->ProcessStartWaitInterval()) == -1) { + print STDERR + "ERROR: cannot find file <$a_srv_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + if ($a_srv[$index]->GetFile ($airplaneiorfile[$index]) == -1) { + print STDERR + "ERROR: cannot retrieve file <$a_srv_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + if ($a_cli[$index]->PutFile ($airplaneiorfile[$index]) == -1) { + print STDERR "ERROR: cannot set file <$a_cli_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + test_info("starting client for $a_srv_name[$index]=" . + $A_CLI[$index]->CommandLine() . "\n"); + my $A_CLI_status = $A_CLI[$index]->Spawn (); + if ($A_CLI_status != 0) { + print STDERR + "ERROR: Airplane Client ($index) failed to spawn returning $A_CLI_status\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + test_info("killing client for $a_srv_name[$index]\n"); + my $A_CLI_status = $A_CLI[$index]->WaitKill ($a_cli[$index]->ProcessStartWaitInterval()); + if ($A_CLI_status != 0) { + print STDERR "ERROR: Airplane Client ($index) returned $A_CLI_status\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + $TI->Arguments ("-ORBInitRef ImplRepoService=file://$ti_imriorfile ". + "shutdown $a_srv_name[$index]"); + test_info("starting TI=" . $TI->CommandLine() . "\n"); + my $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr shutdown returned $TI_status\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + test_info("killing $a_srv_name[$index]\n"); + my $A_SRV_status = $A_SRV[$index]->WaitKill ($a_srv[$index]->ProcessStartWaitInterval()); + if ($A_SRV_status != 0) { + print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + test_info("starting client for $a_srv_name[$index]\n"); + # Should cause the activator to spawn another server. + my $A_CLI_status = $A_CLI[$index]->Spawn (); + if ($A_CLI_status != 0) { + print STDERR "ERROR: Airplane Client 2 ($index) failed to spawn returning $A_CLI_status\n"; + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + test_info("killing client for $a_srv_name[$index]\n"); + # Should cause the activator to spawn another server. + my $A_CLI_status = $A_CLI[$index]->WaitKill ($a_cli[$index]->ProcessStartWaitInterval()); + if ($A_CLI_status != 0) { + print STDERR "ERROR: Airplane Client 2 ($index) returned $A_CLI_status\n"; + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + # Shutdown airplane_server + $TI->Arguments ("-ORBInitRef ImplRepoService=file://$ti_imriorfile ". + "shutdown $a_srv_name[$index]"); + test_info("starting TI=" . $TI->CommandLine() . "\n"); + my $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr shutdown 2 ($index) returned $TI_status\n"; + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + test_info("killing IMR=" . $IMR->CommandLine() . "\n"); + my $IMR_status = $IMR->TerminateWaitKill ($imr->ProcessStopWaitInterval()); + if ($IMR_status != 0) { + print STDERR "ERROR: ImR returned $IMR_status\n"; + $ACT->Kill (); $ACT->TimedWait (1); + return 1; + } + } - # No need to specify imr_initref or -orbuseimr 1 for servers spawned by activator - $TI->Arguments ("-ORBInitRef ImplRepoService=file://$ti_imriorfile ". - "add airplane_server -c \"\\\"$imr_P_SRV_cmd\\\" $refstyle\""); - $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); - if ($TI_status != 0) { - print STDERR "ERROR: tao_imr returned $TI_status\n"; - $p_srv->DeleteFile ($P_SRV_cmd); - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); - return 1; + # Unlink so that we can wait on them again to know the server started. + $imr->DeleteFile ($imriorfile); + $act->DeleteFile ($imriorfile); + $ti->DeleteFile ($imriorfile); + + for ($index = 0; $index < $num_srvr; ++$index) { + $a_srv[$index]->DeleteFile ($imriorfile); } - ## This will write out the imr-ified IOR. Note : If you don't use -orbendpoint - ## when starting the ImR, then this IOR will no longer be valid when the ImR - ## restarts below. You can fix this by creating a new valid IOR, or starting - ## the ImR on a consistent endpoint. - $A_SRV->Arguments ("-o $a_srv_airplaneiorfile -ORBUseIMR 1 $refstyle ". - "-ORBInitRef ImplRepoService=file://$a_srv_imriorfile ". - "-ORBDebugLevel $debug_level"); - $A_SRV_status = $A_SRV->Spawn (); - if ($A_SRV_status != 0) { - print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; + print "Restarting Implementation Repository.\n"; + $IMR->Arguments ("$imr_arguments "); + test_info("restarting IMR=" . $IMR->CommandLine() . "\n"); + $IMR_status = $IMR->Spawn (); + if ($IMR_status != 0) { + print STDERR "ERROR: ImR Service returned $IMR_status\n"; + $ACT->Kill (); $ACT->TimedWait (1); return 1; } - if ($a_srv->WaitForFileTimed ($airplaneiorfile,$a_srv->ProcessStartWaitInterval()) == -1) { - print STDERR "ERROR: cannot find file <$a_srv_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + if ($imr->WaitForFileTimed ($imriorfile, + $imr->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$imr_imriorfile>\n"; $ACT->Kill (); $ACT->TimedWait (1); $IMR->Kill (); $IMR->TimedWait (1); return 1; } - if ($a_srv->GetFile ($airplaneiorfile) == -1) { - print STDERR "ERROR: cannot retrieve file <$a_srv_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + if ($imr->GetFile ($imriorfile) == -1) { + print STDERR "ERROR: cannot retrieve file <$imr_imriorfile>\n"; $ACT->Kill (); $ACT->TimedWait (1); $IMR->Kill (); $IMR->TimedWait (1); return 1; } - if ($a_cli->PutFile ($airplaneiorfile) == -1) { - print STDERR "ERROR: cannot set file <$a_cli_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + if ($act->PutFile ($imriorfile) == -1) { + print STDERR "ERROR: cannot set file <$act_imriorfile>\n"; $ACT->Kill (); $ACT->TimedWait (1); $IMR->Kill (); $IMR->TimedWait (1); return 1; } - - $A_CLI_status = $A_CLI->SpawnWaitKill ($a_cli->ProcessStartWaitInterval()); - if ($A_CLI_status != 0) { - print STDERR "ERROR: Airplane Client returned $A_CLI_status\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + if ($ti->PutFile ($imriorfile) == -1) { + print STDERR "ERROR: cannot set file <$ti_imriorfile>\n"; $ACT->Kill (); $ACT->TimedWait (1); $IMR->Kill (); $IMR->TimedWait (1); return 1; } - $TI->Arguments ("-ORBInitRef ImplRepoService=file://$ti_imriorfile ". - "shutdown airplane_server"); - $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); - if ($TI_status != 0) { - print STDERR "ERROR: tao_imr shutdown returned $TI_status\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); + for ($index = 0; $index < $num_srvr; ++$index) { + if ($a_srv[$index]->PutFile ($imriorfile) == -1) { + print STDERR "ERROR: cannot set file <$a_srv_imriorfile[$index]>\n"; + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + test_info("starting client for $a_srv_name[$index]\n"); + # Should cause the activator to spawn another server. + my $A_CLI_status = $A_CLI[$index]->Spawn (); + if ($A_CLI_status != 0) { + print STDERR "ERROR: Airplane Client 3 ($index) failed to spawn returning $A_CLI_status\n"; + $status = 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + test_info("killing client for $a_srv_name[$index]\n"); + # Should cause the activator to spawn another server. + my $A_CLI_status = $A_CLI[$index]->WaitKill ($a_cli[$index]->ProcessStartWaitInterval()+5); + if ($A_CLI_status != 0) { + print STDERR "ERROR: Airplane Client 3 ($index) returned $A_CLI_status\n"; + $status = 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + # Shutdown airplane_server + $TI->Arguments ("-ORBInitRef ImplRepoService=file://$ti_imriorfile ". + "shutdown $a_srv_name[$index]"); + test_info("starting TI=" . $TI->CommandLine() . "\n"); + my $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr shutdown 3 returned $TI_status\n"; + $status = 1; + } + } + + for ($index = 0; $index < $num_srvr; ++$index) { + test_info("killing ACT\n"); + $ACT_status = $ACT->TerminateWaitKill ($act->ProcessStopWaitInterval()); + if ($ACT_status != 0) { + print STDERR "ERROR: Activator returned $ACT_status\n"; + $status = 1; + } + } + + test_info("killing IMR\n"); + $IMR_status = $IMR->TerminateWaitKill ($imr->ProcessStopWaitInterval()); + if ($IMR_status != 0) { + print STDERR "ERROR: ImR returned $IMR_status\n"; + $status = 1; + } + + if (!defined($backing_store)) { + # startup ImR with "-e" flag to ensure cleanup of registry entries + $IMR->Arguments ("$imr_arguments -e"); + test_info("starting IMR=" . $IMR->CommandLine() . "\n"); + $IMR_status = $IMR->Spawn (); + if ($IMR_status != 0) { + print STDERR "ERROR: ImR Service returned $IMR_status\n"; + return 1; + } + + $IMR->TimedWait ($imr->ProcessStartWaitInterval()); + + test_info("killing IMR\n"); + $IMR_status = $IMR->TerminateWaitKill ($imr->ProcessStopWaitInterval()); + if ($IMR_status != 0) { + print STDERR "ERROR: ImR returned $IMR_status\n"; + $status = 1; + } + } + elsif ($backing_store_flag eq "--directory") { + cleanup_replication($backing_store); + } + else { + $imr->DeleteFile ($backing_store); + } + $imr->DeleteFile ($imriorfile); + $act->DeleteFile ($imriorfile); + $ti->DeleteFile ($imriorfile); + $act->DeleteFile ($actiorfile); + for ($index = 0; $index < $num_srvr; ++$index) { + $imr->DeleteFile ($airplaneiorfile[$index]); + $a_srv[$index]->DeleteFile ($imriorfile); + $a_srv[$index]->DeleteFile ($airplaneiorfile[$index]); + $a_cli[$index]->DeleteFile ($airplaneiorfile[$index]); + $p_srv[$index]->DeleteFile ($P_SRV_cmd[$index]); + } + + return $status; +} + +############################################################################### + +sub failover_test +{ + if (!$replica) { + # The failover test needs the -replica flag + return 0; + } + + my $status = 0; + + my $imr_port = 10001 + $imr->RandomPort (); + my $replica_imr_port = $imr_port + 10; + + my %repo; + setup_repo(\%repo, $imr, $IMR, $imriorfile, $act, $ACT, $actiorfile, $ti, + $TI, $imr_port, "--primary", $backupiorfile); + + my %backup_repo; + setup_repo(\%backup_repo, $replica_imr, $replica_IMR, $replica_imriorfile, + $act, $ACT, $actiorfile, $ti, $TI, + $replica_imr_port, "--backup", $primaryiorfile); + + my @repo_for_srvr; + my @a_srv_imriorfile; + my @imr_airplaneiorfile; + my @a_srv_airplaneiorfile; + for ($index = 0; $index < $num_srvr; ++$index) { + if ($index == ($num_srvr - 1)) { + push(@repo_for_srvr, \%backup_repo); + } else { + push(@repo_for_srvr, \%repo); + } + + push(@a_srv_imriorfile, $a_srv[$index]->LocalFile ($repo_for_srvr[$index]->{imriorfile})); + push(@imr_airplaneiorfile, $repo_for_srvr[$index]->{imr}->LocalFile ($airplaneiorfile[$index])); + push(@a_srv_airplaneiorfile, $a_srv[$index]->LocalFile ($airplaneiorfile[$index])); + $a_srv[$index]->DeleteFile ($repo_for_srvr[$index]->{imriorfile}); + $a_srv[$index]->DeleteFile ($airplaneiorfile[$index]); + $a_cli[$index]->DeleteFile ($airplaneiorfile[$index]); + $repo_for_srvr[$index]->{imr}->DeleteFile ($airplaneiorfile[$index]); + } + $imr->DeleteFile ($imriorfile); + $imr->DeleteFile ($primaryiorfile); + $act->DeleteFile ($imriorfile); + $ti->DeleteFile ($imriorfile); + $act->DeleteFile ($actiorfile); + $replica_imr->DeleteFile ($replica_imriorfile); + $replica_imr->DeleteFile ($backupiorfile); + + print "\n\nstarting primary tao_imr_locator\n"; + $repo{IMR}->Arguments ("-d $test_debug_level -o $repo{imr_imriorfile} " . + "$repo{imr_endpoint_flag} $imr_refstyle $repo{imr_backing_store_flag} "); + my $IMR_status = $repo{IMR}->Spawn (); + if ($IMR_status != 0) { + print STDERR "ERROR: ImR Service returned $IMR_status\n"; return 1; } - $A_SRV_status = $A_SRV->WaitKill ($a_srv->ProcessStartWaitInterval()); - if ($A_SRV_status != 0) { - print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); + if (wait_for_imr(\%backup_repo, "replicaiorfile")) { return 1; } - # Should cause the activator to spawn another server. - $A_CLI_status = $A_CLI->SpawnWaitKill ($a_cli->ProcessStartWaitInterval()); - if ($A_CLI_status != 0) { - print STDERR "ERROR: Airplane Client 2 returned $A_CLI_status\n"; - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); + print "\n\nstarting backup tao_imr_locator\n"; + $backup_repo{IMR}->Arguments ("-d $test_debug_level -o " . + "$backup_repo{imriorfile} $imr_refstyle " . + "$backup_repo{imr_endpoint_flag} " . + "$backup_repo{imr_backing_store_flag}"); + my $replica_IMR_status = $backup_repo{IMR}->Spawn (); + if ($replica_IMR_status != 0) { + print STDERR "ERROR: ImR Service replica returned $replica_IMR_status\n"; + return 1; + } + if (wait_for_imr(\%repo, "replicaiorfile")) { return 1; } + print "started backup tao_imr_locator\n"; - # Shutdown airplane_server - $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); - if ($TI_status != 0) { - print STDERR "ERROR: tao_imr shutdown 2 returned $TI_status\n"; - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); + if (wait_for_imr(\%repo)) { return 1; } + print "started primary tao_imr_locator\n"; - $IMR_status = $IMR->TerminateWaitKill ($imr->ProcessStopWaitInterval()); + for ($index = 0; $index < $num_srvr; ++$index) { + if ($a_srv[$index]->PutFile ($repo_for_srvr[$index]->{imriorfile}) == -1) { + print STDERR "ERROR: cannot set file <$a_srv_imriorfile[$index]>\n"; + kill_imr(); + return 1; + } + } + + print "\n\nstarting tao_imr_activator\n"; + $repo{ACT}->Arguments ("-d $test_debug_level -o $repo{act_actiorfile} " . + "-ORBInitRef ImplRepoService=file://$repo{act_imriorfile} $refstyle " . + $repo{act_explicit_flag}); + my $ACT_status = $repo{ACT}->Spawn (); + if ($ACT_status != 0) { + print STDERR "ERROR: ImR Activator returned $ACT_status\n"; + return 1; + } + + if ($repo{act}->WaitForFileTimed ( + $repo{actiorfile}, + $repo{act}->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <" . + $repo{act_actiorfile} . ">\n"; + kill_act(); + kill_imr(); + return 1; + } + print "started tao_imr_activator\n"; + + if (add_servers (\@repo_for_srvr, \@imr_airplaneiorfile) != 0) { + return 1; + } +# for ($index = 0; $index < $num_srvr; ++$index) { +# print "\n\nadding server $index using tao_imr\n"; +# $repo_for_srvr[$index]->{TI}->Arguments ("-ORBInitRef ImplRepoService" . +# "=file://$repo_for_srvr[$index]->{ti_imriorfile} $refstyle " . +# "add $a_srv_name[$index] -c \"$imr_A_SRV_cmd[$index] " . +# "-o $imr_airplaneiorfile[$index] -s $a_srv_name[$index]\" " . +# "$repo_for_srvr[$index]->{server_act_flag} "); +# my $TI_status = $repo_for_srvr[$index]->{TI}->SpawnWaitKill ( +# $repo_for_srvr[$index]->{ti}->ProcessStartWaitInterval()); +# if ($TI_status != 0) { +# print STDERR "ERROR: tao_imr ($index) returned $TI_status\n"; +# kill_act(); +# kill_imr(); +# return 1; +# } +# print "added server $index with the locator using tao_imr\n"; +# } + + if (add_servers_again (\@repo_for_srvr, \@imr_airplaneiorfile) != 0) { + return 1; + } + + for ($index = 0; $index < $num_srvr; ++$index) { + print "\n\nstarting server $index using tao_imr\n"; + $repo_for_srvr[$index]->{TI}->Arguments ("-ORBInitRef ImplRepoService" . + "=file://$repo_for_srvr[$index]->{ti_imriorfile} $refstyle " . + "start $a_srv_name[$index]"); + my $TI_status = $repo_for_srvr[$index]->{TI}->SpawnWaitKill ( + $repo_for_srvr[$index]->{ti}->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr ($index) returned $TI_status\n"; + kill_act(); + kill_imr(); + return 1; + } + print "started server $index using tao_imr\n"; + } + + for ($index = 0; $index < $num_srvr; ++$index) { + if ($a_srv[$index]->WaitForFileTimed ( + $airplaneiorfile[$index], + $a_srv[$index]->ProcessStartWaitInterval()) == -1) { + print STDERR + "ERROR: cannot find file <$a_srv_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + if ($a_srv[$index]->GetFile ($airplaneiorfile[$index]) == -1) { + print STDERR + "ERROR: cannot retrieve file <$a_srv_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + if ($a_cli[$index]->PutFile ($airplaneiorfile[$index]) == -1) { + print STDERR "ERROR: cannot set file <$a_cli_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + + if (start_clients() != 0) { + return 1; + } + + if (stop_clients() != 0) { + return 1; + } + + if (shutdown_servers_using_tao_imr(\@repo_for_srvr) != 0) { + return 1; + } + + if (start_clients() != 0) { + return 1; + } + + if (stop_clients() != 0) { + return 1; + } + + print "\n\nkilling the primary tao_imr_locator\n"; + $IMR->Kill(); $IMR->TimedWait(); + print "killed the primary tao_imr_locator\n"; + + if (start_clients() != 0) { + return 1; + } + + if (stop_clients() != 0) { + return 1; + } + + if (shutdown_servers_using_tao_imr(\@repo_for_srvr) != 0) { + return 1; + } + + if (add_servers_again(\@repo_for_srvr, \@imr_airplaneiorfile) != 0) { + return 1; + } + + if (remove_servers(\@repo_for_srvr) != 0) { + return 1; + } + + if (add_servers(\@repo_for_srvr, \@imr_airplaneiorfile) != 0) { + return 1; + } + + print "\n\nstarting primary tao_imr_locator again\n"; + $imr->DeleteFile ($imriorfile); + $repo{IMR}->Arguments ("-d $test_debug_level -o $repo{imr_imriorfile} " . + "$imr_refstyle $repo{imr_endpoint_flag} $repo{imr_backing_store_flag}"); + $IMR_status = $repo{IMR}->Spawn (); if ($IMR_status != 0) { - print STDERR "ERROR: ImR returned $IMR_status\n"; - $ACT->Kill (); $ACT->TimedWait (1); + print STDERR "ERROR: ImR Service returned $IMR_status\n"; return 1; } + if (wait_for_imr(\%repo)) { + return 1; + } + print "started primary tao_imr_locator again\n"; - # Unlink so that we can wait on them again to know the server started. + if (start_clients() != 0) { + return 1; + } + + if (stop_clients() != 0) { + return 1; + } + + if (shutdown_servers_using_tao_imr(\@repo_for_srvr) != 0) { + return 1; + } + + print "\n\nkilling the backup tao_imr_locator\n"; + $replica_IMR->Kill(); $replica_IMR->TimedWait(); + $replica_imr->DeleteFile ($replica_imriorfile); + print "killed the backup tao_imr_locator\n"; + + print "\n\nstarting backup tao_imr_locator\n"; + $backup_repo{IMR}->Arguments ("-d $test_debug_level -o " . + "$backup_repo{imriorfile} $imr_refstyle " . + "$backup_repo{imr_endpoint_flag} " . + "$backup_repo{imr_backing_store_flag}"); + $replica_IMR_status = $backup_repo{IMR}->Spawn (); + if ($replica_IMR_status != 0) { + print STDERR "ERROR: ImR Service replica returned $replica_IMR_status\n"; + return 1; + } + if (wait_for_imr(\%repo, "replicaiorfile")) { + return 1; + } + print "started backup tao_imr_locator again\n"; + + if (start_clients() != 0) { + return 1; + } + + if (stop_clients() != 0) { + return 1; + } + + if (shutdown_servers_using_tao_imr(\@repo_for_srvr) != 0) { + return 1; + } + + $IMR->Kill(); $IMR->TimedWait(); + $replica_IMR->Kill(); $replica_IMR->TimedWait(); + $ACT->Kill(); $ACT->TimedWait(); + + cleanup_replication (); + + # clean up IOR files + for ($index = 0; $index < $num_srvr; ++$index) { + $a_srv[$index]->DeleteFile ($repo_for_srvr[$index]->{imriorfile}); + $a_srv[$index]->DeleteFile ($airplaneiorfile[$index]); + $a_cli[$index]->DeleteFile ($airplaneiorfile[$index]); + $repo_for_srvr[$index]->{imr}->DeleteFile ($airplaneiorfile[$index]); + } $imr->DeleteFile ($imriorfile); + $imr->DeleteFile ($primaryiorfile); $act->DeleteFile ($imriorfile); $ti->DeleteFile ($imriorfile); - $a_srv->DeleteFile ($imriorfile); - print "Restarting Implementation Repository.\n"; - $IMR_status = $IMR->Spawn (); + $act->DeleteFile ($actiorfile); + $replica_imr->DeleteFile ($replica_imriorfile); + $replica_imr->DeleteFile ($backupiorfile); + + return $status; +} + +############################################################################### + +sub persistent_ft_test +{ + my $corrupted = shift; + + if (!$corrupted) { + $corrupted = 0; + } + + if (!$replica) { + # The persistent_ft test needs the -replica flag + return 0; + } + + my $status = 0; + + my $imr_port = 10001 + $imr->RandomPort (); + my $replica_imr_port = $imr_port + 1; + + my %repo; + setup_repo(\%repo, $imr, $IMR, $imriorfile, $act, $ACT, $actiorfile, $ti, + $TI, $imr_port, "--primary", $backupiorfile); + + my %backup_repo; + setup_repo(\%backup_repo, $replica_imr, $replica_IMR, $replica_imriorfile, + $act, $ACT, $actiorfile, $ti, $TI, + $replica_imr_port, "--backup", $primaryiorfile); + + my @repo_for_srvr; + my @a_srv_imriorfile; + my @imr_airplaneiorfile; + my @a_srv_airplaneiorfile; + for ($index = 0; $index < $num_srvr; ++$index) { + if ($index == ($num_srvr - 1)) { + push(@repo_for_srvr, \%backup_repo); + } else { + push(@repo_for_srvr, \%repo); + } + + push(@a_srv_imriorfile, $a_srv[$index]->LocalFile ($repo_for_srvr[$index]->{imriorfile})); + push(@imr_airplaneiorfile, $repo_for_srvr[$index]->{imr}->LocalFile ($airplaneiorfile[$index])); + push(@a_srv_airplaneiorfile, $a_srv[$index]->LocalFile ($airplaneiorfile[$index])); + $a_srv[$index]->DeleteFile ($repo_for_srvr[$index]->{imriorfile}); + $a_srv[$index]->DeleteFile ($airplaneiorfile[$index]); + $a_cli[$index]->DeleteFile ($airplaneiorfile[$index]); + $repo_for_srvr[$index]->{imr}->DeleteFile ($airplaneiorfile[$index]); + } + $imr->DeleteFile ($imriorfile); + $imr->DeleteFile ($primaryiorfile); + $act->DeleteFile ($imriorfile); + $ti->DeleteFile ($imriorfile); + $act->DeleteFile ($actiorfile); + $replica_imr->DeleteFile ($replica_imriorfile); + $replica_imr->DeleteFile ($backupiorfile); + + print "\n\nstarting primary tao_imr_locator\n"; + $repo{IMR}->Arguments ("-d $test_debug_level -o $repo{imr_imriorfile} " . + "$imr_refstyle $repo{imr_endpoint_flag} $repo{imr_backing_store_flag}"); +print "Comment line arguments: -d $test_debug_level -o $repo{imr_imriorfile} " . "$imr_refstyle $repo{imr_endpoint_flag} $repo{imr_backing_store_flag}\n"; + my $IMR_status = $repo{IMR}->Spawn (); if ($IMR_status != 0) { print STDERR "ERROR: ImR Service returned $IMR_status\n"; - $ACT->Kill (); $ACT->TimedWait (1); return 1; } - if ($imr->WaitForFileTimed ($imriorfile,$imr->ProcessStartWaitInterval()) == -1) { - print STDERR "ERROR: cannot find file <$imr_imriorfile>\n"; - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); + + if (wait_for_imr(\%backup_repo, "replicaiorfile")) { return 1; } - if ($imr->GetFile ($imriorfile) == -1) { - print STDERR "ERROR: cannot retrieve file <$imr_imriorfile>\n"; - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); + + print "\n\nstarting backup tao_imr_locator\n"; + $backup_repo{IMR}->Arguments ("-d $test_debug_level -o " . + "$backup_repo{imriorfile} $imr_refstyle " . + "$backup_repo{imr_endpoint_flag} " . + "$backup_repo{imr_backing_store_flag}"); + my $replica_IMR_status = $backup_repo{IMR}->Spawn (); + if ($replica_IMR_status != 0) { + print STDERR "ERROR: ImR Service replica returned $replica_IMR_status\n"; return 1; } - if ($act->PutFile ($imriorfile) == -1) { - print STDERR "ERROR: cannot set file <$act_imriorfile>\n"; - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); + if (wait_for_imr(\%repo, "replicaiorfile")) { return 1; } - if ($ti->PutFile ($imriorfile) == -1) { - print STDERR "ERROR: cannot set file <$ti_imriorfile>\n"; - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); + print "started backup tao_imr_locator\n"; + + if (wait_for_imr(\%repo)) { return 1; } - if ($a_srv->PutFile ($imriorfile) == -1) { - print STDERR "ERROR: cannot set file <$a_srv_imriorfile>\n"; - $ACT->Kill (); $ACT->TimedWait (1); - $IMR->Kill (); $IMR->TimedWait (1); + print "started primary tao_imr_locator\n"; + + for ($index = 0; $index < $num_srvr; ++$index) { + if ($a_srv[$index]->PutFile ($repo_for_srvr[$index]->{imriorfile}) == -1) { + print STDERR "ERROR: cannot set file <$a_srv_imriorfile[$index]>\n"; + kill_imr(); + return 1; + } + } + + print "\n\nstarting tao_imr_activator\n"; + $repo{ACT}->Arguments ("-d $test_debug_level -o $repo{act_actiorfile} " . + "-ORBInitRef ImplRepoService=file://$repo{act_imriorfile} $refstyle " . + $repo{act_explicit_flag}); + my $ACT_status = $repo{ACT}->Spawn (); + if ($ACT_status != 0) { + print STDERR "ERROR: ImR Activator returned $ACT_status\n"; return 1; } - # Should cause the activator to spawn another server. - $A_CLI_status = $A_CLI->SpawnWaitKill ($a_cli->ProcessStartWaitInterval()+5); - if ($A_CLI_status != 0) { - print STDERR "ERROR: Airplane Client 3 returned $A_CLI_status\n"; - $status = 1; + if ($repo{act}->WaitForFileTimed ( + $repo{actiorfile}, + $repo{act}->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <" . + $repo{act_actiorfile} . ">\n"; + kill_act(); + kill_imr(); + return 1; + } + print "started tao_imr_activator\n"; + + for ($index = 0; $index < $num_srvr; ++$index) { + print "\n\nupdating server $index using tao_imr\n"; + $repo_for_srvr[$index]->{TI}->Arguments ("-ORBInitRef ImplRepoService" . + "=file://$repo_for_srvr[$index]->{ti_imriorfile} $refstyle " . + "update $a_srv_name[$index] -c \"$imr_A_SRV_cmd[$index] " . + "-o $imr_airplaneiorfile[$index] -s $a_srv_name[$index]\" " . + "$repo_for_srvr[$index]->{server_act_flag} "); + my $TI_status = $repo_for_srvr[$index]->{TI}->SpawnWaitKill ( + $repo_for_srvr[$index]->{ti}->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr ($index) returned $TI_status\n"; + kill_act(); + kill_imr(); + return 1; + } + print "updated server $index with the locator using tao_imr\n"; + } + + for ($index = 0; $index < $num_srvr; ++$index) { + print "\n\nstarting server $index using tao_imr\n"; + $repo_for_srvr[$index]->{TI}->Arguments ("-ORBInitRef ImplRepoService" . + "=file://$repo_for_srvr[$index]->{ti_imriorfile} $refstyle " . + "start $a_srv_name[$index]"); + my $TI_status = $repo_for_srvr[$index]->{TI}->SpawnWaitKill ( + $repo_for_srvr[$index]->{ti}->ProcessStartWaitInterval()); + if ($TI_status != 0) { + print STDERR "ERROR: tao_imr ($index) returned $TI_status\n"; + kill_act(); + kill_imr(); + return 1; + } + print "started server $index using tao_imr\n"; + } + + for ($index = 0; $index < $num_srvr; ++$index) { + if ($a_srv[$index]->WaitForFileTimed ( + $airplaneiorfile[$index], + $a_srv[$index]->ProcessStartWaitInterval()) == -1) { + print STDERR + "ERROR: cannot find file <$a_srv_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + if ($a_srv[$index]->GetFile ($airplaneiorfile[$index]) == -1) { + print STDERR + "ERROR: cannot retrieve file <$a_srv_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + if ($a_cli[$index]->PutFile ($airplaneiorfile[$index]) == -1) { + print STDERR "ERROR: cannot set file <$a_cli_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); + $ACT->Kill (); $ACT->TimedWait (1); + $IMR->Kill (); $IMR->TimedWait (1); + return 1; + } + } + + if (start_clients() != 0) { + return 1; + } + + if (stop_clients() != 0) { + return 1; + } + + if (shutdown_servers_using_tao_imr(\@repo_for_srvr) != 0) { + return 1; + } + + print "\n\nkilling the primary tao_imr_locator\n"; + $IMR->Kill(); $IMR->TimedWait(); + $imr->DeleteFile ($imriorfile); + $imr->DeleteFile ($primaryiorfile); + print "killed the primary tao_imr_locator\n"; + + print "\n\nkilling the backup tao_imr_locator\n"; + $replica_IMR->Kill(); $replica_IMR->TimedWait(); + $replica_imr->DeleteFile ($replica_imriorfile); + $replica_imr->DeleteFile ($backupiorfile); + print "killed the backup tao_imr_locator\n"; + + if($corrupted == 1){ + my $file= "./imr_listing.xml"; + if (open LIST_FILE, ">$file") { + print LIST_FILE "I'm corrupt!!!"; + } + } elsif ($corrupted > 1) { + my $file = "./1_" .($corrupted -1). ".xml"; + if (open LIST_FILE, ">$file") { + print LIST_FILE "I'm corrupt!!!"; + } + } + + + print "\n\nstarting primary tao_imr_locator again\n"; + $repo{IMR}->Arguments ("-d $test_debug_level -o $repo{imr_imriorfile} " . + "$imr_refstyle $repo{imr_endpoint_flag} $repo{imr_backing_store_flag}"); + + my $test_stdout_file = $imr->LocalFile ($stdout_file); + my $test_stderr_file = $imr->LocalFile ($stderr_file); + + $imr->DeleteFile ($stdout_file); + $imr->DeleteFile ($stderr_file); + +# Rely on return value only, so redirect output + redirect_output($test_stdout_file,$test_stderr_file); + $IMR_status = $repo{IMR}->Spawn (); + restore_output(); + + if ($IMR_status != 0) { + print STDERR "ERROR: ImR Service returned $IMR_status\n"; + return 1; } - # Shutdown airplane_server - $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); - if ($TI_status != 0) { - print STDERR "ERROR: tao_imr shutdown 3 returned $TI_status\n"; - $status = 1; + if ($repo{imr}->WaitForFileTimed($primaryiorfile, + $repo{imr}->ProcessStartWaitInterval()) == -1) { + return 1; } - $ACT_status = $ACT->TerminateWaitKill ($act->ProcessStopWaitInterval()); - if ($ACT_status != 0) { - print STDERR "ERROR: Activator returned $ACT_status\n"; - $status = 1; + print "\n\nstarting backup tao_imr_locator again\n"; + $backup_repo{IMR}->Arguments ("-d $test_debug_level -o " . + "$backup_repo{imriorfile} $imr_refstyle " . + "$backup_repo{imr_endpoint_flag} " . + "$backup_repo{imr_backing_store_flag}"); + + redirect_output($test_stdout_file,$test_stderr_file); + $replica_IMR_status = $backup_repo{IMR}->Spawn (); + restore_output(); + + if ($replica_IMR_status != 0) { + print STDERR "ERROR: ImR Service replica returned $replica_IMR_status\n"; + return 1; + } + if ($backup_repo{imr}->WaitForFileTimed($backupiorfile, + $backup_repo{imr}->ProcessStartWaitInterval()) == -1) { + return 1; } + print "started backup tao_imr_locator again\n"; - $IMR_status = $IMR->TerminateWaitKill ($imr->ProcessStopWaitInterval()); - if ($IMR_status != 0) { - print STDERR "ERROR: ImR returned $IMR_status\n"; - $status = 1; + if (start_clients() != 0) { + return 1; + } + + if (stop_clients() != 0) { + return 1; } + if (shutdown_servers_using_tao_imr(\@repo_for_srvr) != 0) { + return 1; + } + + $IMR->Kill(); $IMR->TimedWait(); + $replica_IMR->Kill(); $replica_IMR->TimedWait(); + $ACT->Kill(); $ACT->TimedWait(); + + cleanup_replication (); + + # clean up IOR files + for ($index = 0; $index < $num_srvr; ++$index) { + $a_srv[$index]->DeleteFile ($repo_for_srvr[$index]->{imriorfile}); + $a_srv[$index]->DeleteFile ($airplaneiorfile[$index]); + $a_cli[$index]->DeleteFile ($airplaneiorfile[$index]); + $repo_for_srvr[$index]->{imr}->DeleteFile ($airplaneiorfile[$index]); + } $imr->DeleteFile ($imriorfile); - $imr->DeleteFile ($backing_store); + $imr->DeleteFile ($primaryiorfile); $act->DeleteFile ($imriorfile); $ti->DeleteFile ($imriorfile); - $a_srv->DeleteFile ($imriorfile); $act->DeleteFile ($actiorfile); - $imr->DeleteFile ($airplaneiorfile); - $a_srv->DeleteFile ($airplaneiorfile); - $a_cli->DeleteFile ($airplaneiorfile); - $p_srv->DeleteFile ($P_SRV_cmd); + $replica_imr->DeleteFile ($replica_imriorfile); + $replica_imr->DeleteFile ($backupiorfile); return $status; } @@ -1263,30 +2593,31 @@ sub both_ir_test my $imr_imriorfile = $imr->LocalFile ($imriorfile); my $act_imriorfile = $act->LocalFile ($imriorfile); my $ti_imriorfile = $ti->LocalFile ($imriorfile); - my $a_srv_imriorfile = $a_srv->LocalFile ($imriorfile); + my $a_srv_imriorfile = $a_srv[0]->LocalFile ($imriorfile); my $n_srv_imriorfile = $n_srv->LocalFile ($imriorfile); my $act_actiorfile = $act->LocalFile ($actiorfile); - my $a_srv_airplaneiorfile = $a_srv->LocalFile ($airplaneiorfile); + my $a_srv_airplaneiorfile = $a_srv[0]->LocalFile ($airplaneiorfile[0]); my $n_srv_nesteaiorfile = $n_srv->LocalFile ($nesteaiorfile); my $n_cli_nesteaiorfile = $n_cli->LocalFile ($nesteaiorfile); $imr->DeleteFile ($imriorfile); $act->DeleteFile ($imriorfile); $ti->DeleteFile ($imriorfile); - $a_srv->DeleteFile ($imriorfile); + $a_srv[0]->DeleteFile ($imriorfile); $n_srv->DeleteFile ($imriorfile); $act->DeleteFile ($actiorfile); - $a_srv->DeleteFile ($airplaneiorfile); - $a_cli->DeleteFile ($airplaneiorfile); + $a_srv[0]->DeleteFile ($airplaneiorfile[0]); + $a_cli[0]->DeleteFile ($airplaneiorfile[0]); $n_srv->DeleteFile ($nesteaiorfile); $n_cli->DeleteFile ($nesteaiorfile); - $IMR->Arguments ("-d 2 -t 10 -o $imr_imriorfile $refstyle"); - $IMR_status = $IMR->Spawn (); + $IMR->Arguments ("-d $test_debug_level -t 10 -o $imr_imriorfile $imr_refstyle"); + my $IMR_status = $IMR->Spawn (); if ($IMR_status != 0) { print STDERR "ERROR: ImR Service returned $IMR_status\n"; return 1; } - if ($imr->WaitForFileTimed ($imriorfile,$imr->ProcessStartWaitInterval()) == -1) { + if ($imr->WaitForFileTimed ($imriorfile, + $imr->ProcessStartWaitInterval()) == -1) { print STDERR "ERROR: cannot find file <$imr_imriorfile>\n"; $IMR->Kill (); $IMR->TimedWait (1); return 1; @@ -1306,7 +2637,7 @@ sub both_ir_test $IMR->Kill (); $IMR->TimedWait (1); return 1; } - if ($a_srv->PutFile ($imriorfile) == -1) { + if ($a_srv[0]->PutFile ($imriorfile) == -1) { print STDERR "ERROR: cannot set file <$a_srv_imriorfile>\n"; $IMR->Kill (); $IMR->TimedWait (1); return 1; @@ -1319,8 +2650,8 @@ sub both_ir_test $ACT->Arguments ("-e 16384 -o $act_actiorfile ". "-ORBInitRef ImplRepoService=file://$act_imriorfile ". - "$refstyle -d 2"); - $ACT_status = $ACT->Spawn (); + "$refstyle -d $test_debug_level"); + my $ACT_status = $ACT->Spawn (); if ($ACT_status != 0) { print STDERR "ERROR: ImR Activator returned $ACT_status\n"; return 1; @@ -1339,7 +2670,7 @@ sub both_ir_test # No need to specify imr_initref or -orbuseimr 1 for servers spawned by activator $TI->Arguments ("-ORBInitRef ImplRepoService=file://$ti_imriorfile ". "add nestea_server -c \"$imr_N_SRV_cmd $refstyle\""); - $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); + my $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); if ($TI_status != 0) { print STDERR "ERROR: tao_imr returned $TI_status\n"; $ACT->Kill (); $ACT->TimedWait (1); @@ -1349,7 +2680,7 @@ sub both_ir_test # No need to specify imr_initref or -orbuseimr 1 for servers spawned by activator $TI->Arguments ("-ORBInitRef ImplRepoService=file://$ti_imriorfile ". - "add airplane_server -c \"$imr_A_SRV_cmd $refstyle\""); + "add $a_srv_name[0] -c \"$imr_A_SRV_cmd[0] $refstyle -s $a_srv_name[0]\""); $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); if ($TI_status != 0) { print STDERR "ERROR: tao_imr returned $TI_status\n"; @@ -1361,8 +2692,8 @@ sub both_ir_test $N_SRV->Arguments (" -o $n_srv_nesteaiorfile -ORBUseIMR 1 ". "-ORBInitRef ImplRepoService=file://$n_srv_imriorfile ". "$refstyle ". - "-ORBDebugLevel $debug_level"); - $N_SRV_status = $N_SRV->Spawn (); + "-ORBDebugLevel $srv_debug_level"); + my $N_SRV_status = $N_SRV->Spawn (); if ($N_SRV_status != 0) { print STDERR "ERROR: Nestea Server returned $N_SRV_status\n"; $N_SRV->Kill (); $N_SRV->TimedWait (1); @@ -1392,38 +2723,38 @@ sub both_ir_test return 1; } - $A_SRV->Arguments (" -o $a_srv_airplaneiorfile -ORBUseIMR 1 ". - "-ORBInitRef ImplRepoService=file://$n_srv_imriorfile ". - "$refstyle ". - "-ORBDebugLevel $debug_level"); - $A_SRV_status = $A_SRV->Spawn (); + $A_SRV[0]->Arguments ( + " -o $a_srv_airplaneiorfile -ORBUseIMR 1 ". + "-ORBInitRef ImplRepoService=file://$n_srv_imriorfile ". + "$refstyle -ORBDebugLevel $srv_debug_level -s $a_srv_name[0]"); + my $A_SRV_status = $A_SRV[0]->Spawn (); if ($A_SRV_status != 0) { print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + kill_then_timed_wait(\@A_SRV, 1); $N_SRV->Kill (); $N_SRV->TimedWait (1); $ACT->Kill (); $ACT->TimedWait (1); $IMR->Kill (); $IMR->TimedWait (1); return 1; } - if ($a_srv->WaitForFileTimed ($airplaneiorfile,$a_srv->ProcessStartWaitInterval()) == -1) { + if ($a_srv[0]->WaitForFileTimed ($airplaneiorfile[0],$a_srv[0]->ProcessStartWaitInterval()) == -1) { print STDERR "ERROR: cannot find file <$a_srv_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + kill_then_timed_wait(\@A_SRV, 1); $N_SRV->Kill (); $N_SRV->TimedWait (1); $ACT->Kill (); $ACT->TimedWait (1); $IMR->Kill (); $IMR->TimedWait (1); return 1; } - if ($a_srv->GetFile ($airplaneiorfile) == -1) { + if ($a_srv[0]->GetFile ($airplaneiorfile[0]) == -1) { print STDERR "ERROR: cannot retrieve file <$a_srv_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + kill_then_timed_wait(\@A_SRV, 1); $N_SRV->Kill (); $N_SRV->TimedWait (1); $ACT->Kill (); $ACT->TimedWait (1); $IMR->Kill (); $IMR->TimedWait (1); return 1; } - if ($a_cli->PutFile ($airplaneiorfile) == -1) { - print STDERR "ERROR: cannot set file <$a_cli_airplaneiorfile>\n"; - $A_SRV->Kill (); $A_SRV->TimedWait (1); + if ($a_cli[0]->PutFile ($airplaneiorfile[0]) == -1) { + print STDERR "ERROR: cannot set file <$a_cli_airplaneiorfile[$index]>\n"; + kill_then_timed_wait(\@A_SRV, 1); $N_SRV->Kill (); $N_SRV->TimedWait (1); $ACT->Kill (); $ACT->TimedWait (1); $IMR->Kill (); $IMR->TimedWait (1); @@ -1441,7 +2772,7 @@ sub both_ir_test print "\n## Spawning multiple simultaneous clients with both servers running.\n"; map $_->Spawn(), @a_clients; map $_->Spawn(), @n_clients; - map $_->WaitKill($a_cli->ProcessStopWaitInterval()), @a_clients; + map $_->WaitKill($a_cli[0]->ProcessStopWaitInterval()), @a_clients; map $_->WaitKill($n_cli->ProcessStopWaitInterval()), @n_clients; $TI->Arguments ("-ORBInitRef ImplRepoService=file://$n_srv_imriorfile ". @@ -1453,14 +2784,14 @@ sub both_ir_test } $TI->Arguments ("-ORBInitRef ImplRepoService=file://$n_srv_imriorfile ". - "shutdown airplane_server"); + "shutdown $a_srv_name[0]"); $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); if ($TI_status != 0) { print STDERR "ERROR: tao_imr returned $TI_status\n"; $status = 1; } - $A_SRV_status = $A_SRV->WaitKill ($a_srv->ProcessStopWaitInterval()); + $A_SRV_status = $A_SRV[0]->WaitKill ($a_srv[0]->ProcessStopWaitInterval()); if ($A_SRV_status != 0) { print STDERR "ERROR: Airplane Server returned $A_SRV_status\n"; $status = 1; @@ -1475,7 +2806,7 @@ sub both_ir_test map $_->Spawn(), @a_clients; map $_->Spawn(), @n_clients; - map $_->WaitKill($a_cli->ProcessStopWaitInterval()), @a_clients; + map $_->WaitKill($a_cli[0]->ProcessStopWaitInterval()), @a_clients; map $_->WaitKill($n_cli->ProcessStopWaitInterval()), @n_clients; $TI->Arguments ("-ORBInitRef ImplRepoService=file://$n_srv_imriorfile ". @@ -1487,7 +2818,7 @@ sub both_ir_test } $TI->Arguments ("-ORBInitRef ImplRepoService=file://$n_srv_imriorfile ". - "shutdown airplane_server"); + "shutdown $a_srv_name[0]"); $TI_status = $TI->SpawnWaitKill ($ti->ProcessStartWaitInterval()); if ($TI_status != 0) { print STDERR "ERROR: tao_imr returned $TI_status\n"; @@ -1509,11 +2840,11 @@ sub both_ir_test $imr->DeleteFile ($imriorfile); $act->DeleteFile ($imriorfile); $ti->DeleteFile ($imriorfile); - $a_srv->DeleteFile ($imriorfile); + $a_srv[0]->DeleteFile ($imriorfile); $n_srv->DeleteFile ($imriorfile); $act->DeleteFile ($actiorfile); - $a_srv->DeleteFile ($airplaneiorfile); - $a_cli->DeleteFile ($airplaneiorfile); + $a_srv[0]->DeleteFile ($airplaneiorfile[0]); + $a_cli[0]->DeleteFile ($airplaneiorfile[0]); $n_srv->DeleteFile ($nesteaiorfile); $n_cli->DeleteFile ($nesteaiorfile); @@ -1526,16 +2857,52 @@ sub both_ir_test # Parse the arguments my $ret = 0; +my $test_num = 0; + +my @tests = ("airplane", "airplane_ir", "nestea", "nestea_ir", + "both_ir", "persistent_ir", "persistent_ir_hash", + "persistent_ir_shared", "persistent_ft", "failover"); +my @nt_tests = ("nt_service_ir", "persistent_ir_registry"); + +my $i; +if ($all_tests) { + push(@ARGV, @tests); +} -if ($#ARGV >= 0) { -for (my $i = 0; $i <= $#ARGV; $i++) { +if ($#ARGV == -1) { + $ret = both_ir_test(); +} + +my $append = ""; +for ($i = 0; $i <= $#ARGV; $i++) { if ($ARGV[$i] eq "-h" || $ARGV[$i] eq "-?") { - print "run_test test\n"; + print "run_test [options] test\n"; print "\n"; + print "options \n"; + print " -debug -- set debug_level to 10\n"; + print " -tdebug -- set the tests debug level to 10\n"; + print " -all -- causes all tests to run (except nt_service_ir and\n"; + print " persistent_ir_registry)\n"; + print " -servers -- run tests with more than 1 server and client\n"; + print " -replica -- run tests with more than 1 server and client interacting\n"; + print " with replicated ImR Locators\n"; print "test -- Runs a specific test:\n"; - print " airplane, airplane_ir, nt_service_ir, ", - "nestea, nestea_ir,\n"; - print " both_ir, persistent_ir\n"; + my $indent = " "; + print "$indent"; + my $count = 0; + my @all_tests = @tests; + push(@all_tests, @nt_tests); + foreach my $test (@all_tests) { + if (++$count > 1) { + print ",$append"; + } + print "$test"; + $append = ""; + if ($count % 3 == 0) { + $append = "\n$indent"; + } + } + print "\n"; exit 1; } elsif ($ARGV[$i] eq "airplane") { @@ -1557,7 +2924,31 @@ for (my $i = 0; $i <= $#ARGV; $i++) { $ret = both_ir_test (); } elsif ($ARGV[$i] eq "persistent_ir") { - $ret = persistent_ir_test (); + $ret = persistent_ir_test ("-x"); + } + elsif ($ARGV[$i] eq "persistent_ir_hash") { + $ret = persistent_ir_test ("-p"); + } + elsif ($ARGV[$i] eq "persistent_ir_registry") { + $ret = persistent_ir_test ("-r"); + } + elsif ($ARGV[$i] eq "persistent_ir_shared") { + $ret = persistent_ir_test ("--directory"); + } + elsif ($ARGV[$i] eq "persistent_ft") { + $ret = persistent_ft_test (); + } + elsif ($ARGV[$i] eq "persistent_listingcorrupt") { + $ret = persistent_ft_test (1); + } + elsif ($ARGV[$i] eq "persistent_activatorcorrupt") { + $ret = persistent_ft_test (2); + } + elsif ($ARGV[$i] eq "persistent_servercorrupt") { + $ret = persistent_ft_test (3); + } + elsif ($ARGV[$i] eq "failover") { + $ret = failover_test (); } elsif ($ARGV[$i] eq "perclient") { $ret = perclient(); @@ -1565,12 +2956,12 @@ for (my $i = 0; $i <= $#ARGV; $i++) { elsif ($ARGV[$i] eq "shutdown") { $ret = shutdown_repo(); } - else { + elsif ($ARGV[$i] !~ /^-/) { print "run_test: Unknown Option: ".$ARGV[$i]."\n"; } -} -} else { - $ret = both_ir_test(); + if ($ret != 0) { + last; + } } exit $ret; diff --git a/TAO/orbsvcs/tests/Notify/Bug_1884_Regression/common.h b/TAO/orbsvcs/tests/Notify/Bug_1884_Regression/common.h index 4ba52e0064b..4f9a251dfcd 100644 --- a/TAO/orbsvcs/tests/Notify/Bug_1884_Regression/common.h +++ b/TAO/orbsvcs/tests/Notify/Bug_1884_Regression/common.h @@ -61,12 +61,12 @@ get_event_channel(CORBA::ORB_ptr orb) else { try { - ec = factory->get_event_channel(channelIdSeq[0]); + ec = factory->get_event_channel(channelIdSeq.in()[0]); } catch (CosNotifyChannelAdmin::ChannelNotFound& ) { std::cerr << "ChannelNotFound: " - << channelIdSeq[0] << std::endl; + << channelIdSeq.in()[0] << std::endl; throw; } diff --git a/TAO/orbsvcs/tests/Notify/Bug_1884_Regression/filter.cpp b/TAO/orbsvcs/tests/Notify/Bug_1884_Regression/filter.cpp index 8c3ac52b03a..6612fc33e43 100644 --- a/TAO/orbsvcs/tests/Notify/Bug_1884_Regression/filter.cpp +++ b/TAO/orbsvcs/tests/Notify/Bug_1884_Regression/filter.cpp @@ -68,12 +68,12 @@ get_event_channel(CORBA::ORB_ptr orb) else { try { - ec = factory->get_event_channel(channelIdSeq[0]); + ec = factory->get_event_channel(channelIdSeq.in()[0]); } catch (CosNotifyChannelAdmin::ChannelNotFound&) { std::cerr << "ChannelNotFound: " - << channelIdSeq[0] << std::endl; + << channelIdSeq.in()[0] << std::endl; exit(1); } diff --git a/TAO/orbsvcs/tests/Notify/Bug_3688_Regression/common.h b/TAO/orbsvcs/tests/Notify/Bug_3688_Regression/common.h index 4ba52e0064b..4f9a251dfcd 100755 --- a/TAO/orbsvcs/tests/Notify/Bug_3688_Regression/common.h +++ b/TAO/orbsvcs/tests/Notify/Bug_3688_Regression/common.h @@ -61,12 +61,12 @@ get_event_channel(CORBA::ORB_ptr orb) else { try { - ec = factory->get_event_channel(channelIdSeq[0]); + ec = factory->get_event_channel(channelIdSeq.in()[0]); } catch (CosNotifyChannelAdmin::ChannelNotFound& ) { std::cerr << "ChannelNotFound: " - << channelIdSeq[0] << std::endl; + << channelIdSeq.in()[0] << std::endl; throw; } diff --git a/TAO/orbsvcs/tests/Notify/Persistent_Filter/Filter.cpp b/TAO/orbsvcs/tests/Notify/Persistent_Filter/Filter.cpp index 70e81593cce..548705dcfe7 100644 --- a/TAO/orbsvcs/tests/Notify/Persistent_Filter/Filter.cpp +++ b/TAO/orbsvcs/tests/Notify/Persistent_Filter/Filter.cpp @@ -287,7 +287,7 @@ FilterClient::get_EC () const int TIMEOUT = 20; while (i < TIMEOUT) { - CosNotifyChannelAdmin::ChannelIDSeq_var ids + const CosNotifyChannelAdmin::ChannelIDSeq_var ids = notify_factory_->get_all_channels (); if (ids->length () > 0) @@ -350,7 +350,7 @@ FilterClient::create_supplieradmin () void FilterClient::get_supplieradmin () { - CosNotifyChannelAdmin::AdminIDSeq_var ids + const CosNotifyChannelAdmin::AdminIDSeq_var ids = ec_->get_all_supplieradmins(); ACE_ASSERT (ids->length () == 1); @@ -429,7 +429,7 @@ FilterClient::create_consumeradmin () void FilterClient::get_consumeradmin () { - CosNotifyChannelAdmin::AdminIDSeq_var ids + const CosNotifyChannelAdmin::AdminIDSeq_var ids = ec_->get_all_consumeradmins(); ACE_ASSERT (ids->length () == 2); @@ -460,7 +460,7 @@ FilterClient::verify_filter (CosNotifyFilter::FilterAdmin_var& admin, ACE_UNUSED_ARG (constraint_expr); // only used to validate assert, which is // compiled out for nondebug builds. - CosNotifyFilter::FilterIDSeq_var ids + const CosNotifyFilter::FilterIDSeq_var ids = admin->get_all_filters (); ACE_ASSERT (ids->length () == 1); diff --git a/TAO/orbsvcs/tests/Redundant_Naming/client.cpp b/TAO/orbsvcs/tests/Redundant_Naming/client.cpp index f54ada2e199..483b787c224 100644 --- a/TAO/orbsvcs/tests/Redundant_Naming/client.cpp +++ b/TAO/orbsvcs/tests/Redundant_Naming/client.cpp @@ -16,6 +16,7 @@ #include "tao/debug.h" #include "ace/Get_Opt.h" #include "ace/OS_NS_stdio.h" +#include "ace/High_Res_Timer.h" #if defined (_MSC_VER) # pragma warning (disable : 4250) @@ -184,6 +185,7 @@ ACE_TMAIN(int argc, ACE_TCHAR *argv[]) level1[0].id = CORBA::string_dup ("level1_context"); CosNaming::NamingContext_var level1_context; level1_context = root_context_1->bind_new_context (level1); + for (i=0; i<o_breath; i++) { // Instantiate a dummy object and bind it under the new context. @@ -191,12 +193,11 @@ ACE_TMAIN(int argc, ACE_TCHAR *argv[]) Test_Object_var obj1 = impl1->_this (); impl1->_remove_ref (); - CosNaming::Name obj_name; - obj_name.length (1); + level1.length (2); char wide_name[16]; ACE_OS::sprintf(wide_name, "obj_%d", i); - obj_name[0].id = CORBA::string_dup (wide_name); - level1_context->bind (obj_name, obj1.in ()); + level1[1].id = CORBA::string_dup (wide_name); + root_context_1->bind (level1, obj1.in ()); } } @@ -449,6 +450,94 @@ ACE_TMAIN(int argc, ACE_TCHAR *argv[]) } ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Redundancy test OK\n"))); + + // Test performance of binding a bunch of objects in one context + try + { + // Bind one context level under root. + CosNaming::Name level1; + level1.length (1); + level1[0].id = CORBA::string_dup ("perf_context"); + CosNaming::NamingContext_var perf_context; + perf_context = root_context_1->bind_new_context (level1); + + // Instantiate a dummy object and bind it under the new context. + My_Test_Object *impl1 = new My_Test_Object (i+1); + Test_Object_var obj1 = impl1->_this (); + impl1->_remove_ref (); + + int test_runs = 100; + ACE_High_Res_Timer::global_scale_factor_type gsf = + ACE_High_Res_Timer::global_scale_factor (); + + ACE_hrtime_t start = ACE_OS::gethrtime (); + + // Test how long it takes to bind + for (i=0; i<test_runs; i++) + { + level1.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "obj_%d", i); + level1[0].id = CORBA::string_dup (wide_name); + perf_context->bind (level1, obj1.in ()); + } + + ACE_hrtime_t elapsed_time = ACE_OS::gethrtime () - start; + // convert to microseconds + ACE_UINT32 usecs = ACE_UINT32(elapsed_time / gsf); + double secs = usecs / 1000000.0; + + ACE_DEBUG ((LM_DEBUG, + "Bound %i objects in %.2f secs\n", + test_runs, secs)); + + // Test how long it takes to resolve + start = ACE_OS::gethrtime (); + for (i=0; i<test_runs; i++) + { + level1.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "obj_%d", i); + level1[0].id = CORBA::string_dup (wide_name); + CORBA::Object_var result_obj_ref = perf_context->resolve (level1); + } + + elapsed_time = ACE_OS::gethrtime () - start; + // convert to microseconds + usecs = ACE_UINT32(elapsed_time / gsf); + secs = ((ACE_INT32) usecs) / 1000000.0; + + ACE_DEBUG ((LM_DEBUG, + "Resolved %i objects in %.2f secs\n", + test_runs, secs)); + + // Test how long it takes to unbind + start = ACE_OS::gethrtime (); + for (i=0; i<test_runs; i++) + { + level1.length (1); + char wide_name[16]; + ACE_OS::sprintf(wide_name, "obj_%d", i); + level1[0].id = CORBA::string_dup (wide_name); + perf_context->unbind (level1); + } + + elapsed_time = ACE_OS::gethrtime () - start; + // convert to microseconds + usecs = ACE_UINT32(elapsed_time / gsf); + secs = ((ACE_INT32) usecs) / 1000000.0; + + ACE_DEBUG ((LM_DEBUG, + "Unbound %i objects in %.2f secs\n", + test_runs, secs)); + } + catch (const CORBA::Exception& ex) + { + ex._tao_print_exception (ACE_TEXT ("ERROR: Exception during performance test.\n")); + return -1; + } + + // All tests have passed up to this point return 0; } diff --git a/TAO/orbsvcs/tests/Redundant_Naming/run_test.pl b/TAO/orbsvcs/tests/Redundant_Naming/run_test.pl index 849a56c486c..e89dc202e66 100755 --- a/TAO/orbsvcs/tests/Redundant_Naming/run_test.pl +++ b/TAO/orbsvcs/tests/Redundant_Naming/run_test.pl @@ -77,12 +77,12 @@ else { # Run two Naming Servers in redundant mode and one client. Client uses iors # in files to find the individual copies of the Naming Servers. -my $args = "-ORBEndPoint $ns_endpoint1 -o $test_iorfile1 -m 0 -r NameService"; +my $args = "-ORBEndPoint $ns_endpoint1 -o $iorfile1 -m 0 -r NameService"; my $prog = "$startdir/../../Naming_Service/tao_cosnaming"; $NS1 = $test->CreateProcess ("$prog", "$args"); -$test->DeleteFile ("iorfile1"); +$test->DeleteFile ($iorfile1); $NS1->Spawn (); @@ -98,7 +98,7 @@ $prog = "$startdir/../../Naming_Service/tao_cosnaming"; $NS2 = $test->CreateProcess ("$prog", "$args"); -$test->DeleteFile ("iorfile2"); +$test->DeleteFile ($iorfile2); $NS2->Spawn (); @@ -129,7 +129,7 @@ if ($client != 0) { $NS1->Kill (); $NS2->Kill (); -$test->DeleteFile ("iorfile1"); -$test->DeleteFile ("iorfile2"); +$test->DeleteFile ($iorfile1); +$test->DeleteFile ($iorfile2); exit $status; diff --git a/TAO/orbsvcs/tests/Simple_Naming/client.cpp b/TAO/orbsvcs/tests/Simple_Naming/client.cpp index d8996e15ceb..f965e7607de 100644 --- a/TAO/orbsvcs/tests/Simple_Naming/client.cpp +++ b/TAO/orbsvcs/tests/Simple_Naming/client.cpp @@ -276,7 +276,11 @@ MT_Test::svc (void) } if (name_service.in () == 0) - return -1; + { + ACE_ERROR ((LM_ERROR, + "ERROR: Unable to narrow naming IOR to a NamingContext.\n")); + return -1; + } // Bind the object. try @@ -344,6 +348,7 @@ MT_Test::svc (void) { ACE_DEBUG ((LM_DEBUG, "Unable to unbind in thread %t\n")); + return -1; } catch (const CORBA::Exception& ex) { @@ -915,7 +920,9 @@ Iterator_Test::execute (TAO_Naming_Client &root_context) || bindings_list->length () != 1 || bindings_list[0u].binding_type != CosNaming::nobject) ACE_ERROR_RETURN ((LM_ERROR, - "CosNaming::list does not function properly\n"), + "Iterator_Test -> CosNaming::list does not function properly. \ +Should have returned one CosNaming::nobject element in bindings_list. Length = %d, \ +Binding Type = %d\n", bindings_list->length (), bindings_list[0u].binding_type), -1); ACE_DEBUG ((LM_DEBUG, "First binding: %C\n", @@ -1214,7 +1221,7 @@ Persistent_List_Test::execute (TAO_Naming_Client &root_context) if (CORBA::is_nil (iter.in ()) || bindings_list->length () != 0) ACE_ERROR_RETURN ((LM_ERROR, - "CosNaming::list does not function properly\n"), + "Persistent_List_Test -> CosNaming::list does not function properly. Should have returned an iterator.\n"), -1); while (iter->next_one (binding.out ())) @@ -1270,7 +1277,7 @@ Persistent_List_Test::execute (TAO_Naming_Client &root_context) if (CORBA::is_nil (iter.in ()) || bindings_list->length () != 0) ACE_ERROR_RETURN ((LM_ERROR, - "CosNaming::list does not function properly\n"), + "Persistent_List_Test -> CosNaming::list does not function properly. Should have returned an iterator.\n"), -1); while (iter->next_one (binding.out ())) diff --git a/TAO/orbsvcs/tests/Simple_Naming/run_test_ffp.pl b/TAO/orbsvcs/tests/Simple_Naming/run_test_ffp.pl index 5ef2c750ed4..df18c6ccee3 100755 --- a/TAO/orbsvcs/tests/Simple_Naming/run_test_ffp.pl +++ b/TAO/orbsvcs/tests/Simple_Naming/run_test_ffp.pl @@ -37,6 +37,7 @@ $persistent_ior_file = "pns.ior"; my $test_iorfile = $test->LocalFile ($iorfile); my $test_persistent_ior_file = $test->LocalFile ($persistent_ior_file); +my $prog = "../../Naming_Service/tao_cosnaming"; $test->DeleteFile($iorfile); $test->DeleteFile($persistent_ior_file); @@ -44,7 +45,7 @@ $test->DeleteFile($persistent_ior_file); sub name_server { my $args = "-ORBNameServicePort $ns_multicast_port -o $test_iorfile -m 1 @_"; - my $prog = "../../Naming_Service/tao_cosnaming"; + $SV = $test->CreateProcess ("$prog", "$args"); @@ -95,14 +96,50 @@ $hostname = $test->HostName (); "Flat File Persistent Test (Part 2): \n", "Flat File Persistent Test (Part 3): \n"); -$test_number = 0; -$test->DeleteFile($test_persistent_ior_file); +sub run_test +{ + $prog = "@_"; + + $test_number = 0; + + $test->DeleteFile($test_persistent_ior_file); + + if ( ! -d "NameService" ) { + mkdir (NameService, 0777); + } + else { + chdir "NameService"; + opendir(THISDIR, "."); + @allfiles = grep(!/^\.\.?$/, readdir(THISDIR)); + closedir(THISDIR); + foreach $tmp (@allfiles){ + $test->DeleteFile ($tmp); + } + chdir ".."; + } + + # Run server and client for each of the tests. Client uses ior in a + # file to bootstrap to the server. + foreach $o (@opts) { + name_server ($server_opts[$test_number]); + + print STDERR "\n ".$comments[$test_number]; + + client ($o); + + $SV->Kill (); + + ## For some reason, only on Windows XP, we need to + ## wait before starting another tao_cosnaming when + ## the mmap persistence option is used + if ($^O eq "MSWin32") { + sleep(1); + } + + $test_number++; + } -if ( ! -d "NameService" ) { - mkdir (NameService, 0777); -} -else { chdir "NameService"; opendir(THISDIR, "."); @allfiles = grep(!/^\.\.?$/, readdir(THISDIR)); @@ -111,40 +148,19 @@ else { $test->DeleteFile ($tmp); } chdir ".."; -} - -# Run server and client for each of the tests. Client uses ior in a -# file to bootstrap to the server. -foreach $o (@opts) { - name_server ($server_opts[$test_number]); - - print STDERR "\n ".$comments[$test_number]; + rmdir "NameService"; - client ($o); - - $SV->Kill (); - - ## For some reason, only on Windows XP, we need to - ## wait before starting another tao_cosnaming when - ## the mmap persistence option is used - if ($^O eq "MSWin32") { - sleep(1); - } - - $test_number++; + $test->DeleteFile($persistent_ior_file); + $test->DeleteFile($iorfile); } -chdir "NameService"; -opendir(THISDIR, "."); -@allfiles = grep(!/^\.\.?$/, readdir(THISDIR)); -closedir(THISDIR); -foreach $tmp (@allfiles){ - $test->DeleteFile ($tmp); -} -chdir ".."; -rmdir "NameService"; +@server_exes = ("../../Naming_Service/tao_cosnaming", + "../../Naming_Service/tao_ft_naming"); -$test->DeleteFile($persistent_ior_file); -$test->DeleteFile($iorfile); +foreach $e (@server_exes) { + print STDERR "Testing Naming Service Executable: $e\n"; + run_test($e); + print STDERR "======================================\n"; +} exit $status; diff --git a/TAO/orbsvcs/tests/Simple_Naming/run_test_ft.pl b/TAO/orbsvcs/tests/Simple_Naming/run_test_ft.pl new file mode 100755 index 00000000000..37d6ec95f46 --- /dev/null +++ b/TAO/orbsvcs/tests/Simple_Naming/run_test_ft.pl @@ -0,0 +1,217 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +# This is a Perl script that runs some Naming Service tests +# for the FT_Naming_Service. +# It runs all the tests that will run with min CORBA. +# It starts all the servers and clients as necessary. + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::TestTarget; +use Cwd; + +## Save the starting directory +$status = 0; +$multicast = '224.9.9.2'; +$startdir = getcwd(); + +$quiet = 0; + +# check for -q flag +if ($ARGV[0] eq '-q') { + $quiet = 1; +} + +my $test = PerlACE::TestTarget::create_target (1) || die "Create target 1 failed\n"; + +# Variables for command-line arguments to client and server +# executables. +$ns_multicast_port = 10001 + $test->RandomPort(); # Can not be 10000 on Chorus 4.0 + +$iorfile = "ns.ior"; +$persistent_ior_file = "pns.ior"; +$persistent_log_file = "test_log"; + +$data_file = "test_run.data"; + +## Allow the user to determine where the persistent file will be located +## just in case the current directory is not suitable for locking. +## We can't change the name of the persistent file because that is not +## sufficient to work around locking problems for Tru64 when the current +## directory is NFS mounted from a system that does not properly support +## locking. +foreach my $possible ($ENV{TMPDIR}, $ENV{TEMP}, $ENV{TMP}) { + if (defined $possible && -d $possible) { + if (chdir($possible)) { + last; + } + } +} + +$test_log = $test->LocalFile ($data_file); +$test->DeleteFile ($data_file); + +#Files which used by test +my $test_iorfile = $test->LocalFile ($iorfile); +my $test_persistent_log_file = $test->LocalFile ($persistent_log_file); +my $test_persistent_ior_file = $test->LocalFile ($persistent_ior_file); + +$test->DeleteFile($persistent_ior_file); +$test->DeleteFile($iorfile); +$test->DeleteFile($persistent_log_file); + +sub name_server +{ + my $args = "-u NameService -ORBMulticastDiscoveryEndpoint $multicast:$ns_multicast_port -o $test_iorfile -m 1 @_"; + my $prog = "$startdir/../../Naming_Service/tao_ft_naming"; + + $SV = $test->CreateProcess ("$prog", "$args"); + + $test->DeleteFile($iorfile); + + $SV->Spawn (); + + if ($test->WaitForFileTimed ($iorfile, + $test->ProcessStartWaitInterval()) == -1) { + print STDERR "ERROR: cannot find file <$test_iorfile>\n"; + $SV->Kill (); $SV->TimedWait (1); + exit 1; + } + + sleep(10); +} + +sub client +{ + my $args = "@_"." "; + my $prog = "$startdir/client"; + + $CL = $test->CreateProcess ("$prog", "$args"); + + $client_status = $CL->SpawnWaitKill ($test->ProcessStartWaitInterval() + 45); + + if ($client_status != 0) { + print STDERR "ERROR: client returned $client_status\n"; + $status = 1; + } + +} + +sub make_or_clean_state +{ + # Create a directory to hold the persistent state + if ( ! -d "NameService" ) { + mkdir (NameService, 0777); + } + else { + chdir "NameService"; + opendir(THISDIR, "."); + @allfiles = grep(!/^\.\.?$/, readdir(THISDIR)); + closedir(THISDIR); + foreach $tmp (@allfiles){ + $test->DeleteFile ($tmp); + } + chdir ".."; + } +} + +## The options below have been reordered due to a +## initialization problem (within the Naming_Service) +## that has only been seen on Windows XP. + +# Options for all simple tests recognized by the 'client' program. +@opts = ("-s -ORBInitRef NameService=file://$test_iorfile", + "-s -ORBInitRef NameService=mcast://$multicast:$ns_multicast_port\::/NameService", + "-t -ORBInitRef NameService=file://$test_iorfile", + "-i -ORBInitRef NameService=file://$test_iorfile", + "-e -ORBInitRef NameService=file://$test_iorfile", + "-y -ORBInitRef NameService=file://$test_iorfile" + ); + +@server_opts = ("-t 30", + "", + "", + "", + "", + "" + ); + +@comments = ("Simple Test: \n", + "Simple Test (using multicast to locate the server): \n", + "Tree Test: \n", + "Iterator Test: \n", + "Exceptions Test: \n", + "Destroy Test: \n" + ); + +$test_number = 0; + +print "INFO: Running the test in ", getcwd(), "\n"; + +# Run server and client for each of the tests. Client uses ior in a +# file to bootstrap to the server. +foreach $o (@opts) { + + # Ensure that the name service is starting clean each time + make_or_clean_state; + + print STDERR "Running Test: $comments[$test_number]\n"; + + name_server ($server_opts[$test_number]); + + client ($o); + + $SV->Kill (); + + ## For some reason, only on Windows XP, we need to + ## wait before starting another tao_cosnaming when + ## the mmap persistence option is used + if ($^O eq "MSWin32") { + sleep(1); + } + $test_number++; +} + +$test->DeleteFile($persistent_ior_file); +$test->DeleteFile($persistent_log_file); +$test->DeleteFile($iorfile); + +# Now run the multithreaded test, sending output to the file. +print STDERR "\n Multithreaded Test:\n"; +$test->DeleteFile ($data_file); + +name_server (); +client ("-ORBInitRef NameService=file://$test_iorfile -ORBLogFile $test_log", "-m15"); + +$SV->Kill (); + +$errors = system ("perl $startdir/process-m-output.pl $test_log 15") >> 8; + +if ($errors > 0) { + $status = 1; + + if (!$quiet) { + print STDERR "Errors Detected, printing output\n"; + if (open (DATA, "<$test_log")) { + print STDERR "================================= Begin\n"; + print STDERR <DATA>; + print STDERR "================================= End\n"; + close (DATA); + } + else { + print STDERR "ERROR: Could not open $test_log\n"; + } + $test->DeleteFile ($data_file); + } +} + +$test->DeleteFile($iorfile); +# Remove the persistence directory +rmdir "NameService"; + + +exit $status; |