diff options
author | wilson_d <wilson_d@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2004-10-07 15:07:04 +0000 |
---|---|---|
committer | wilson_d <wilson_d@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2004-10-07 15:07:04 +0000 |
commit | 77c566edf39533401136410e0f00dbfd7e525fd1 (patch) | |
tree | 0b6bff61c6c1d96a3a819596f7f329effb3a57b6 | |
parent | 699787b7ccfd5da1c7ad001fec91e815e163e16b (diff) | |
download | ATCD-77c566edf39533401136410e0f00dbfd7e525fd1.tar.gz |
ChangeLogTag: Thu Oct 7 09:40:51 2004 Dale Wilson <wilson_d@ociweb.com>
127 files changed, 13992 insertions, 136 deletions
diff --git a/TAO/ChangeLog_pnotify b/TAO/ChangeLog_pnotify new file mode 100644 index 00000000000..5b3d2a6cca5 --- /dev/null +++ b/TAO/ChangeLog_pnotify @@ -0,0 +1,179 @@ +Thu Oct 7 09:40:51 2004 Dale Wilson <wilson_d@ociweb.com> + + * ChangeLog_pnotify: + + * docs/notification/reliability.html: + + * orbsvcs/orbsvcs/CosNotification.mpc: + * orbsvcs/orbsvcs/Notify/Admin.h: + * orbsvcs/orbsvcs/Notify/Admin.inl: + * orbsvcs/orbsvcs/Notify/Admin.cpp: + * orbsvcs/orbsvcs/Notify/AdminProperties.h: + * orbsvcs/orbsvcs/Notify/AdminProperties.inl: + * orbsvcs/orbsvcs/Notify/AdminProperties.cpp: + * orbsvcs/orbsvcs/Notify/AllocTracker.h: + * orbsvcs/orbsvcs/Notify/Bit_Vector.h: + * orbsvcs/orbsvcs/Notify/Bit_Vector.cpp: + * orbsvcs/orbsvcs/Notify/Builder.h: + * orbsvcs/orbsvcs/Notify/Builder.cpp: + * orbsvcs/orbsvcs/Notify/ConsumerAdmin.h: + * orbsvcs/orbsvcs/Notify/ConsumerAdmin.cpp: + * orbsvcs/orbsvcs/Notify/CosNotify_Service.cpp: + * orbsvcs/orbsvcs/Notify/Delivery_Method.h: + * orbsvcs/orbsvcs/Notify/Delivery_Method.cpp: + * orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.h: + * orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.cpp: + * orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.h: + * orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.cpp: + * orbsvcs/orbsvcs/Notify/Delivery_Request.h: + * orbsvcs/orbsvcs/Notify/Delivery_Request.cpp: + * orbsvcs/orbsvcs/Notify/EventChannel.h: + * orbsvcs/orbsvcs/Notify/EventChannel.cpp: + * orbsvcs/orbsvcs/Notify/EventChannelFactory.h: + * orbsvcs/orbsvcs/Notify/EventChannelFactory.cpp: + * orbsvcs/orbsvcs/Notify/EventType.h: + * orbsvcs/orbsvcs/Notify/EventType.cpp: + * orbsvcs/orbsvcs/Notify/EventTypeSeq.h: + * orbsvcs/orbsvcs/Notify/EventTypeSeq.cpp: + * orbsvcs/orbsvcs/Notify/Event_Manager.cpp: + * orbsvcs/orbsvcs/Notify/Event_Persistence_Factory.h: + * orbsvcs/orbsvcs/Notify/Event_Persistence_Strategy.h: + * orbsvcs/orbsvcs/Notify/FilterAdmin.h: + * orbsvcs/orbsvcs/Notify/FilterAdmin.cpp: + * orbsvcs/orbsvcs/Notify/ID_Factory.h: + * orbsvcs/orbsvcs/Notify/ID_Factory.inl: + * orbsvcs/orbsvcs/Notify/ID_Factory.cpp: + * orbsvcs/orbsvcs/Notify/Name_Value_Pair.h: + * orbsvcs/orbsvcs/Notify/Name_Value_Pair.inl: + * orbsvcs/orbsvcs/Notify/Name_Value_Pair.cpp: + * orbsvcs/orbsvcs/Notify/Object.h: + * orbsvcs/orbsvcs/Notify/Object.inl: + * orbsvcs/orbsvcs/Notify/Object.cpp: + * orbsvcs/orbsvcs/Notify/POA_Helper.h: + * orbsvcs/orbsvcs/Notify/POA_Helper.cpp: + * orbsvcs/orbsvcs/Notify/Peer.h: + * orbsvcs/orbsvcs/Notify/Persistent_File.h: + * orbsvcs/orbsvcs/Notify/Persistent_File.cpp: + * orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.h: + * orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.cpp: + * orbsvcs/orbsvcs/Notify/Properties.h: + * orbsvcs/orbsvcs/Notify/Properties.inl: + * orbsvcs/orbsvcs/Notify/PropertySeq.h: + * orbsvcs/orbsvcs/Notify/PropertySeq.inl: + * orbsvcs/orbsvcs/Notify/PropertySeq.cpp: + * orbsvcs/orbsvcs/Notify/Property_Boolean.h: + * orbsvcs/orbsvcs/Notify/Property_Boolean.inl: + * orbsvcs/orbsvcs/Notify/Property_T.h: + * orbsvcs/orbsvcs/Notify/Property_T.inl: + * orbsvcs/orbsvcs/Notify/Proxy.h: + * orbsvcs/orbsvcs/Notify/Proxy.cpp: + * orbsvcs/orbsvcs/Notify/ProxyConsumer.cpp: + * orbsvcs/orbsvcs/Notify/ProxySupplier.h: + * orbsvcs/orbsvcs/Notify/ProxySupplier.cpp: + * orbsvcs/orbsvcs/Notify/ProxySupplier_T.cpp: + * orbsvcs/orbsvcs/Notify/Proxy_T.cpp: + * orbsvcs/orbsvcs/Notify/QoSProperties.h: + * orbsvcs/orbsvcs/Notify/QoSProperties.inl: + * orbsvcs/orbsvcs/Notify/QoSProperties.cpp: + * orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.h: + * orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.cpp: + * orbsvcs/orbsvcs/Notify/Reconnection_Registry.h: + * orbsvcs/orbsvcs/Notify/Reconnection_Registry.inl: + * orbsvcs/orbsvcs/Notify/Reconnection_Registry.cpp: + * orbsvcs/orbsvcs/Notify/Routing_Slip.h: + * orbsvcs/orbsvcs/Notify/Routing_Slip.cpp: + * orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.h: + * orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.cpp: + * orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.h: + * orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.cpp: + * orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.h: + * orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.cpp: + * orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.h: + * orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.cpp: + + * orbsvcs/orbsvcs/Notify/SupplierAdmin.h: + * orbsvcs/orbsvcs/Notify/SupplierAdmin.cpp: + * orbsvcs/orbsvcs/Notify/Topology_Factory.h: + * orbsvcs/orbsvcs/Notify/Topology_Loader.h: + * orbsvcs/orbsvcs/Notify/Topology_Loader.cpp: + * orbsvcs/orbsvcs/Notify/Topology_Object.h: + * orbsvcs/orbsvcs/Notify/Topology_Object.inl: + * orbsvcs/orbsvcs/Notify/Topology_Object.cpp: + * orbsvcs/orbsvcs/Notify/Topology_Saver.h: + * orbsvcs/orbsvcs/Notify/Topology_Saver.cpp: + * orbsvcs/orbsvcs/Notify/XML_Loader.h: + * orbsvcs/orbsvcs/Notify/XML_Loader.cpp: + * orbsvcs/orbsvcs/Notify/XML_Saver.h: + * orbsvcs/orbsvcs/Notify/XML_Saver.cpp: + * orbsvcs/orbsvcs/Notify/XML_Topology_Factory.h: + * orbsvcs/orbsvcs/Notify/XML_Topology_Factory.cpp: + * orbsvcs/orbsvcs/Notify/notify_persist_export.h: + * orbsvcs/orbsvcs/Notify/Any/CosEC_ProxyPushConsumer.h: + * orbsvcs/orbsvcs/Notify/Any/CosEC_ProxyPushConsumer.cpp: + * orbsvcs/orbsvcs/Notify/Any/CosEC_ProxyPushSupplier.h: + * orbsvcs/orbsvcs/Notify/Any/CosEC_ProxyPushSupplier.cpp: + * orbsvcs/orbsvcs/Notify/Any/ProxyPushConsumer.h: + * orbsvcs/orbsvcs/Notify/Any/ProxyPushConsumer.cpp: + * orbsvcs/orbsvcs/Notify/Any/ProxyPushSupplier.h: + * orbsvcs/orbsvcs/Notify/Any/ProxyPushSupplier.cpp: + * orbsvcs/orbsvcs/Notify/Any/PushConsumer.h: + * orbsvcs/orbsvcs/Notify/Any/PushConsumer.cpp: + * orbsvcs/orbsvcs/Notify/Any/PushSupplier.h: + * orbsvcs/orbsvcs/Notify/Any/PushSupplier.cpp: + + * orbsvcs/orbsvcs/Notify/Sequence/SequenceProxyPushConsumer.h: + * orbsvcs/orbsvcs/Notify/Sequence/SequenceProxyPushConsumer.cpp: + * orbsvcs/orbsvcs/Notify/Sequence/SequenceProxyPushSupplier.h: + * orbsvcs/orbsvcs/Notify/Sequence/SequenceProxyPushSupplier.cpp: + * orbsvcs/orbsvcs/Notify/Sequence/SequencePushConsumer.h: + * orbsvcs/orbsvcs/Notify/Sequence/SequencePushConsumer.cpp: + * orbsvcs/orbsvcs/Notify/Sequence/SequencePushSupplier.h: + * orbsvcs/orbsvcs/Notify/Sequence/SequencePushSupplier.cpp: + + * orbsvcs/orbsvcs/Notify/Structured/StructuredProxyPushConsumer.h: + * orbsvcs/orbsvcs/Notify/Structured/StructuredProxyPushConsumer.cpp: + * orbsvcs/orbsvcs/Notify/Structured/StructuredProxyPushSupplier.h: + * orbsvcs/orbsvcs/Notify/Structured/StructuredProxyPushSupplier.cpp: + * orbsvcs/orbsvcs/Notify/Structured/StructuredPushConsumer.h: + * orbsvcs/orbsvcs/Notify/Structured/StructuredPushConsumer.cpp: + * orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.h: + * orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.cpp: + + * orbsvcs/orbsvcs/NotifyExt.idl: + + * orbsvcs/tests/Notify/PluggableTopology/PlugTop.mpc: + * orbsvcs/tests/Notify/PluggableTopology/Test_Saver.h: + * orbsvcs/tests/Notify/PluggableTopology/Test_Saver.cpp: + * orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.h: + * orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.cpp: + * orbsvcs/tests/Notify/PluggableTopology/main.cpp: + * orbsvcs/tests/Notify/PluggableTopology/plugtop_export.h: + * orbsvcs/tests/Notify/PluggableTopology/plugtop_ns.conf: + + * orbsvcs/tests/Notify/Reconnecting/Consumer.h: + * orbsvcs/tests/Notify/Reconnecting/Consumer.cpp: + * orbsvcs/tests/Notify/Reconnecting/README: + * orbsvcs/tests/Notify/Reconnecting/Reconnecting.mpc: + * orbsvcs/tests/Notify/Reconnecting/Supplier.h: + * orbsvcs/tests/Notify/Reconnecting/Supplier.cpp: + * orbsvcs/tests/Notify/Reconnecting/event.conf: + * orbsvcs/tests/Notify/Reconnecting/ns_mt.conf: + * orbsvcs/tests/Notify/Reconnecting/ns_mt_both.conf: + * orbsvcs/tests/Notify/Reconnecting/ns_mt_topo.conf: + * orbsvcs/tests/Notify/Reconnecting/ns_st.conf: + * orbsvcs/tests/Notify/Reconnecting/ns_st_both.conf: + * orbsvcs/tests/Notify/Reconnecting/ns_st_topo.conf: + * orbsvcs/tests/Notify/Reconnecting/run_test.pl: + + * orbsvcs/tests/Notify/XML_Persistence/XML_Persistence.mpc: + * orbsvcs/tests/Notify/XML_Persistence/main.cpp: + * orbsvcs/tests/Notify/XML_Persistence/run_test.pl: + * orbsvcs/tests/Notify/XML_Persistence/svc.conf: + + * orbsvcs/tests/Notify/lib/Periodic_Consumer.cpp: + + Merge OCI's Notification Service Changes into DOC group. + Connectivity (i.e. topology) persistence is working + Event persistence is not, yet. + + diff --git a/TAO/docs/notification/reliability.html b/TAO/docs/notification/reliability.html new file mode 100644 index 00000000000..44c9c198035 --- /dev/null +++ b/TAO/docs/notification/reliability.html @@ -0,0 +1,346 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> + <head> + <title>Using the Reliable Notification Service</title> + <meta content="False" name="vs_snapToGrid"> + <meta content="False" name="vs_showGrid"> + <!-- $Id$ --> + </head> + <body> + <h1>Using the Reliable Notification Service</h1> + <h2>Background</h2> + <p>There are two CORBA services defined by the OMG to support the + Supplier/Consumer design pattern. This pattern allows messages (known as + Events in this context) to be generated by one or more suppliers and delivered + to one or more consumers without requiring that the suppliers and consumers + have any knowledge of each other. </p> + <P>The Event Service provides a basic implementation of this pattern, and the + Notification service extends this basic service to support a rich variety of + optional features.</P> + <h2>Reliability and Persistence</h2> + <p>One of the optional features of the Notification service is Reliability. + By default the Event Service and the Notification service provide a <EM>best-effort</EM> + support for event delivery. If things go wrong -- program crashes, + communications failures, etc. events may be lost without notice.</p> + <P>There are some circumstances in which losing events is not + acceptable. The Notification service may be used for these situations if + it is configured for reliable operation. Reliable operation is not + available in the Event Service. Reliable operation means information is + saved persistently (usually on a disk file) and used to recover from the + various failures that might otherwise lead to loss of data.</P> + <P>There are two separate, but related, issues that need to be addressed to + provide reliable event delivery: topology persistence an event + persistence.</P> + <P>To provide topology persistence, sometimes called connection persistence, the + Notification service must keep track of what clients (Suppliers and Consumers) + have connected to the Notification service and what options have been specified + to contol the delivery of events.</P> + <P>To provide event persistence the Notification service tracks each event in + persistent storage to be sure it is delivered to every consumer that should + receive it. + </P> + <P>There may be situations in which topology persistence is all that is necessary + -- it may be acceptable to lose events during a failure as long as + the system is restored to normal operation afterward. Event persistence + on the other hand can only be supported if topology persistence is also being + used. It doesn't help to keep track of events if the system is unable to + find the consumers to which the events should be delivered.</P> + <P>Two separate issues must be addressed as part of setting up the Notifcation + for reliable operation. At the system administration level the + Notification service must be configured for topology persistence and + possibly for event persistence. At the application level, programs + that operate as consumers and suppliers must set the appropriate parameters to + enable reliable operation, and must cooperate with the reconnection process + that occurs during topology recovery.</P> + <h2>Configuring Notification Service Reliability.</h2> + <h3>Service Configurator Changes</h3> + <P>Runtime configuration of the Notification Service is supported through the + service configurator file. This file is normally named svc.conf; however the + -ORBSvcConf command line option allows an alternate service configuration file + to be specified. + </P> + <P> + Service configuration changes to support Notification Service reliability + include a new option on the existing <code>Notify_Default_Event_Manager_Objects_Factory</code> + service configuration command, and two new service configuration commands. + </P> + <H4>Notify_Default_Event_Manager_Objects_Factory option: -AllowReconnect</H4> + <p>Certain recovery cases require that a Consumer be able to reconnect to an + existing proxy object in the Notification Service in order to receive all + events delivered by that proxy object. This behavior is a departure from the + OMG Specification which mandates that the Notification Service should throw an + "Already Connected" exception when a consumer attempts to connect to a proxy + that was previously used by another Consumer. + </p> + <p>A new option, -AllowReconnect, is available for the existing <code>Notify_Default_Event_Manager_Objects_Factory + </code>command to support this requirement. As an example of its use, the + following line configures the Notification Service for multi-threaded operation + supporting reconnection.</p> + <code>static Notify_Default_Event_Manager_Objects_Factory "-DispatchingThreads 2 + -SourceThreads 2 -AllowReconnect" </code> + <H3>Configuring Connection (Topologogy) Reliability</H3> + <p>The support for persistent topology is actually a configurable strategy. + TAO includes an XML Topology Persistence Strategy that uses an XML file for + persistent storage, but it it is designed to allow other strategies to be + developed. For example if topology information should be stored in a + relational database file, it is possible to develop a persistent topology + strategy to do so. The details of doing this are beyond the scope of this + document. + </p> + <P>This document describes how to configure the XML topology persistence included + with TAO.</P> + <P>An example of the service configuration command to configure the XML + strategy is: + </P> + <p><code>dynamic Topology_Factory Service_Object* + TAO_CosNotification_persist:_make_XML_Topology_Factory() "-base_path ./reconnect_test" </code> + </p> + <p>The first part of this line: <code>dynamic Topology_Factory Service_Object* + TAO_CosNotification_persist:_make_XML_Topology_Factory()</code>should be given + exactly as shown. For details on this syntax, see chapter 17 of the TAO + Developer's Guide. + </p> + <P>The quoted string at the end of the line contain arguments for the configured + strategy. The arguments recognized by the XML topology strategy implemented in + this project are: + </P> + <ul> + <li> + -v + <li> + -base_path <EM>file_path</EM> + <li> + -backup_count <EM>count</EM> + <li> + -save_base_path <EM>file_path</EM> + <li> + -load_base_path <EM>file_path</EM> + <li> + <H4>-no_timestamp + </H4> + </li> + </ul> + <H4>Topology_Factory Option: -v</H4> + To help diagnose and/or document svc.conf settings, the "-v" will cause the + options for the Topology_Factory to be displayed as they are interpreted + <H4>Topology_Factory Option: -base_path file_path + </H4> + <P>The argument for this option is a fully qualified path name without an + extension for the xml file in which topology information is saved. Three + extensions will be appended to this name: .new, .xml, and .000 + </P> + <P>Saved topology information will be written to <EM>file_path</EM>.new file. + Information with a .new extension is not necessarily complete and will not be + used to restore the topology. + </P> + <P>When the .new file is complete, the previous <EM>file_path</EM>.000 (if any) + will be deleted, the previous <EM>file_path</EM>.xml (if any) will be renamed + as <EM>file_path</EM>.000 and the <EM>file_path</EM>.new file will be renamed + as file_path.xml. The assumption is that a file system rename operation is + atomic. If this assumption holds than at any time the file <EM>file_path</EM>.xml + (if it exists) contains the most recent complete save. If <EM>file_path</EM>.xml + does not exist then <EM>file_path</EM>.000 contains the most recent complete + save. If neither of these files exist the saved topology information is not + available. + </P> + <H4>Topology_Factory Option: -backup_count count</H4> + <P>This option modifies the behavior described in the preceeding section to allow + additional backup copies of the topology file to be retained. The default + value, 1, means that only the <EM>file_path</EM>.000 file will be kept. If a + higher number is specified, then older versions will be kept. Rather than + deleting <EM>file_path</EM>.000, the system will rename it to be <EM>file_path.</EM>001. + Older versions will be named <EM>file_path</EM>.002, <EM>file_path</EM>.002 and + so on. + </P> + <P>Under normal circumstances only one backup file is required -- in fact these + additional backup files will not be used to restore the topoogy. However + setting this number to a larger value lets the system keep a brief history of + topology changes. Since the XML files are roughly human-readable this can be + used as a diagnostic tool for problems related to Notification Service + topology. + </P> + <H4>Topology_Factory Options: -save_base_path file_path and -load_base_path + file_path + </H4> + <P>These options are alternatives to the -base_path option. They allow the file + from which topology information is loaded at Notification Service startup time + to be different from the file to which this information is saved as the system + runs. + </P> + <P>This option is mostly used for developer testing, a system administrator may + find an interesting use for this option -- possibly involving script files that + rename the XML files during recovery from a Notification Service failure. + </P> + <H4>Topology_Factory Option: -no_timestamp</H4> + <P>The XML files include a timestamp to indicate when the information was saved. + The timestamp is for information only and is not needed for correct functioning + of the topology persistence. This option suppresses that timestamp. Doing so + makes it possible to compare XML files using a program like diff to see if the + files represent the same topology. + </P> + <P>This option is intended primarily for testing the persistent topology + implementation. + </P> + <h3>Configuring Event Reliability</h3> + <p>A service configuraton new object, "Event_Persistence", can be configured in + the service configuration file to enable and configure the Event Reliability. + An example of the line needed to configure the Event_Persistence object is: + </p> + <p><code>dynamic Event_Persistence Service_Object* + TAO_CosNotification_persist:_make_Standard_Event_Persistence() "-v -file_path + ./event_persist.db" </code> + </p> + <p><CODE></CODE>If this line does not appear in svc.conf, then event reliability + will not be supported. QoS parameters for reliable event delivery will be + silently ignored when Event Reliability is not configured. Event reliability + also requires topology reliability, so if this line appears there must also be + a "Topology_Factory" line in the file. If not, the Notification Service will + fail to start up. + </p> + <P>The beginning of this line, up to and including the parentheses, should appear + exactly as shown. For details on this syntax, see chapter 17 of the TAO + Developer's Guide. The quoted string at the end of the line contains options + for Event_Persistence. + </P> + <h4>Event_Persistence Option: -v</h4> + <p>This option and any option that appears after this option will be written to + the log (normally the console) as it is processed. This is intended to help + diagnose and document the Event Persistence settings. The default is to + configure Event Persistence silently. + </p> + <h4>Event_Persistence Option: -file_path path + </h4> + <p>This option gives the completely qualified name for the file in which + persistent event information will be stored. The file should be configured on a + reliable device that supports synchronized writes (i.e. flushing the operating + system's write cache.) A device that is suitable for storing a reliable + database would be appropriate for storing this file. The file will be subject + to a relatively high number of small (single block) write requests, but very + few, if any, read requests. If the file does not exist, then a new file will be + created. If the file does exist, and if topology is successfully loaded, the + events from this file will be reloaded and redelivered automatically. This is a + required option. There is no default value. + </p> + <h4>Event_Persistence Option: -block_size n + </h4> + <p>This option gives the block size in bytes for the device on which the event + reliability file is stored. For both performance and reliability reasons it is + important that the value matches the physical characteristics of the device. + The default value is 512. + </p> + <h2>Application Programming Changes to Support Reliability</h2> + <p> + When it is configured as described above, the Notification service + supports reliable connectivity and/or event delivery. + Actually achieving such reliability, however, requires cooperation from the + Notification service clients (Suppliers and Consumers). + <P> + There are a number of failure possibilities and different recovery techniques + are needed to handle them. The simplest case is when a client + fails and is restarted. + <P> + The Notification service will have maintained the connection points (Supplier + and Consumer Admins, Proxy Consumers, Proxy Admins, etc.) As each of these + connections was established, an ID returned by the notification + service. An application that wishes to be reconnected after a failure + should save a persistent copy of these IDs. For example, it could write + the IDs to a file, then read them back from the file after restarting. + Using these ID's the application can reconnect to the existing connection + points in the Notification service. The reconnection to the Proxy objects + will only work if the Notification service has been configured with the + -AllowReconnection option described above, but otherwise this process is fairly + straightforward. + <P> + As soon as a supplier has reconnected, it can resume sending events. As + soon as a consumer has reconnected, persistent events (if any) and new events + will start to arrive. + <P> + Notice that the identity of a consumer or supplier is determined by these saved + IDs. This is true even if the restarted client is running on a completely + different machine from the original client. + <P> + The case of the Notification service itself failing then being restarted on the + same or a different machine is somewhat more complicated. The + Notification service wasn't designed to initiate a connection to a + client. It must wait for the client to reconnect before it can start + accepting or delivering events. The difficulty is in having the client + know when to initiatie the reconnection, and to where the Notification service + is running in case it was necessary to move it to a new machine due to the + failure + <H3>Reconnection Registry</H3> + <p>The reconnection registry provides an answer to the question of how the client + knows where and when to reconnect to the Notification service. This + TAO-specific interface is implemented by the EventChannelFactory in the + reliable Notification Service. Clients can narrow the EventChannelFactory + object reference to a Reconnection Registery interface, then register a + Reconnection Callback object that will be notified when the Notification + service has restarted and is ready for reconections. The + EventChannelFactory passes its own object reference to the Reconnection + Callback object to inform the client where the Notification service is now + running.</p> + <P>The interfaces involved are defined in the NotifyExt.idl file (in + $TAO_ROOT/orbsvcs/orbsvcs) and are shown here:</P> + <pre> + /** * \brief An interface which gets registered with a + ReconnectionRegistry. + * * A supplier or consumer must implement this interface in order + to * allow the Notification Service to attempt to reconnect to it + after * a failure. The supplier or consumer must register its instance + of * this interface with the + ReconnectionRegistry. + */ interface + ReconnectionCallback + { /// Perform operations to reconnect to the Notification + Service /// after a + failure. void reconnect (in Object + + new_connection); /// Check to see if the ReconnectionCallback is alive + boolean is_alive (); + }; + + /** + * \brief An interface that handles registration of suppliers and consumers. + * + * This registry should be implemented by an EventChannelFactory and + * will call the appropriate reconnect methods for all ReconnectionCallback + * objects registered with it. + */ + interface ReconnectionRegistry + { + typedef unsigned long ReconnectionID; + ReconnectionID register_callback(in ReconnectionCallback reconection); + + void unregister_callback (in ReconnectionID id); + + /// Check to see if the ReconnectionRegistry is alive + boolean is_alive (); + }; + </pre> + <H3>Using Event Reliability</H3> + <P>Configuring the Notification service for reliable event delivery is necessary, + but not sufficient to enable reliable handling of events. The application + code in either the client or the server must configure the EventChannel through + which the events are delivered to operate in the reliable mode. This is + done by setting the QoSProperties named "ConnectionReliabilty" and + "EventReliability" to the value "persistent" -- either at the time the channel + is created or at a later time useing the set_qos method.</P> + <P>Once an channel has been configured for reliable operation, persistence can be + disabled on an event by event basis using QoSProperties of the event + itself. This could be none, for examlpe, to avoid the overhead of + persistently storing events for which reliability is not needed.</P> + <P>The supplier sends events to the EventChannel using a push() method. For + persistent events, this call will not return to the supplier until the + Notification service is prepared to guarantee event delivery. + </P> + <P>Application code in the Consumer should be written with the knowledge that + events are guaranteed to be delivered, but during recovery from a failure there + is a possiblity that an event may arrive more than once. This could + happen, for example if the event was in the process of being delivered at the + time the failure occurred and the failure prevents the Notfication service from + determining if the delivery completed successfully. To meet its + committment that every event will be delivered, the Notification service will + retry the delivery in this canse which may result in a duplicate event.</P> + <P>As long as this situation is understood at the time the application is + designed, it should be possible for the application to handle this situation.</P> + </body> +</html> diff --git a/TAO/orbsvcs/orbsvcs/CosNotification.mpc b/TAO/orbsvcs/orbsvcs/CosNotification.mpc index 103a53192cb..02ed4b8dc8b 100644 --- a/TAO/orbsvcs/orbsvcs/CosNotification.mpc +++ b/TAO/orbsvcs/orbsvcs/CosNotification.mpc @@ -47,8 +47,7 @@ project(CosNotification) : orbsvcslib, core, event { Template_Files { } - - // explicit Resource_Files to avoid including _Skel & _Serv rc files. + Resource_Files{ CosNotification.rc } @@ -151,6 +150,7 @@ project(CosNotification_Serv) : orbsvcslib, core, notification_skel, dynamicany, Notify/Method_Request_Lookup.cpp Notify/Method_Request_Shutdown.cpp Notify/Method_Request_Updates.cpp + Notify/Name_Value_Pair.cpp Notify/Notify_Constraint_Interpreter.cpp Notify/Notify_Constraint_Visitors.cpp Notify/Notify_Default_Collection_Factory.cpp @@ -170,12 +170,16 @@ project(CosNotification_Serv) : orbsvcslib, core, notification_skel, dynamicany, Notify/QoSProperties.cpp Notify/Reactive_Task.cpp Notify/Refcountable.cpp + Notify/Reconnection_Registry.cpp Notify/Subscription_Change_Worker.cpp Notify/Supplier.cpp Notify/SupplierAdmin.cpp Notify/ThreadPool_Task.cpp Notify/Timer_Queue.cpp Notify/Timer_Reactor.cpp + Notify/Topology_Loader.cpp + Notify/Topology_Object.cpp + Notify/Topology_Saver.cpp Notify/Worker_Task.cpp Notify/Any/AnyEvent.cpp Notify/Any/CosEC_ProxyPushConsumer.cpp @@ -200,3 +204,20 @@ project(CosNotification_Serv) : orbsvcslib, core, notification_skel, dynamicany, Template_Files { } } + +//project(CosNotification_Persist) : orbsvcslib, core, notification, event_skel, portableserver, acexml { +project(CosNotification_Persist) : notification_serv, acexml { + sharedname = TAO_CosNotification_Persist + dynamicflags = TAO_NOTIFY_PERSIST_BUILD_DLL + + IDL_Files { + } + Source_Files { + Notify/XML_Loader.cpp + Notify/XML_Saver.cpp + Notify/XML_Topology_Factory.cpp + } + + Template_Files { + } +} diff --git a/TAO/orbsvcs/orbsvcs/Notify/Admin.cpp b/TAO/orbsvcs/orbsvcs/Notify/Admin.cpp index c01902fea7e..fdfd7bb73c6 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Admin.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/Admin.cpp @@ -14,11 +14,18 @@ ACE_RCSID (Notify, #include "Container_T.h" #include "Proxy.h" #include "EventChannel.h" - -TAO_Notify_Admin::TAO_Notify_Admin (void) +#include "Topology_Saver.h" +#include "Save_Persist_Worker_T.h" +#include "Reconnect_Worker_T.h" +#include "tao/debug.h" +//#define DEBUG_LEVEL 9 +#define DEBUG_LEVEL TAO_debug_level + +TAO_Notify_Admin::TAO_Notify_Admin () : ec_ (0) , proxy_container_ (0) , filter_operator_ (CosNotifyChannelAdmin::OR_OP) + , is_default_ (false) { // Initialize all Admin objects to initially be subscribed for all events. // This is a reasonable default and is required to allow Cos Event consumers/suppliers to send/receive events, @@ -37,7 +44,7 @@ TAO_Notify_Admin::init (TAO_Notify_EventChannel *ec ACE_ENV_ARG_DECL) this->ec_->_incr_refcnt (); - this->TAO_Notify_Object::init (ec); + this->TAO_NOTIFY::Topology_Object::init (ec); ACE_NEW_THROW_EX (this->proxy_container_, TAO_Notify_Proxy_Container (), @@ -91,6 +98,104 @@ TAO_Notify_Admin::insert (TAO_Notify_Proxy* proxy ACE_ENV_ARG_DECL) this->proxy_container_->insert (proxy ACE_ENV_ARG_PARAMETER); } +void +TAO_Notify_Admin::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL) +{ + bool changed = this->children_changed_; + this->children_changed_ = false; + this->self_changed_ = false; + + if (is_persistent ()) + { + TAO_NOTIFY::NVPList attrs; + this->save_attrs(attrs); + + const char* type = this->get_admin_type_name(); + + bool want_all_children = + saver.begin_object(this->id(), type, attrs, changed ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + if (want_all_children || this->filter_admin_.is_changed ()) + { + this->filter_admin_.save_persistent(saver ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + if (want_all_children || this->subscribed_types_.is_changed ()) + { + this->subscribed_types_.save_persistent(saver ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + + TAO_NOTIFY::Save_Persist_Worker<TAO_Notify_Proxy> wrk(saver, want_all_children); + this->proxy_container_->collection()->for_each(&wrk ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + saver.end_object(this->id(), type ACE_ENV_ARG_PARAMETER); + } +} + +void +TAO_Notify_Admin::save_attrs (TAO_NOTIFY::NVPList& attrs) +{ + TAO_Notify_Object::save_attrs(attrs); + attrs.push_back(TAO_NOTIFY::NVP("InterFilterGroupOperator", this->filter_operator_)); + if (this->is_default_) + { + attrs.push_back (TAO_NOTIFY::NVP ("default", "yes")); + } +} + +void +TAO_Notify_Admin::load_attrs(const TAO_NOTIFY::NVPList& attrs) +{ + TAO_Notify_Object::load_attrs (attrs); + const char * value = 0; + if (attrs.find ("InterFilterGroupOperator", value)) + { + this->filter_operator_ = static_cast <CosNotifyChannelAdmin::InterFilterGroupOperator> (ACE_OS::atoi (value)); + } + if (attrs.find ("default", value)) + { + this->is_default_ = ACE_OS::strcmp (value, "yes"); + } +} + +TAO_NOTIFY::Topology_Object* +TAO_Notify_Admin::load_child (const ACE_CString &type, + CORBA::Long id, const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL) +{ + TAO_NOTIFY::Topology_Object* result = this; + if (type == "subscriptions") + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Admin reload subscription %d\n") + , ACE_static_cast (int, id) + )); + // since we initialized our subscribed types to everything + // in the constructor. we have to clear it out first. + this->subscribed_types_.reset(); + result = &this->subscribed_types_; + } + else if (type == "filter_admin") + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Admin reload filter_admin %d\n") + , ACE_static_cast (int, id) + )); + result = & this->filter_admin_; + } + return result; +} + +void +TAO_Notify_Admin::reconnect (ACE_ENV_SINGLE_ARG_DECL) +{ + TAO_NOTIFY::Reconnect_Worker<TAO_Notify_Proxy> wrk; + this->proxy_container_->collection()->for_each(&wrk ACE_ENV_ARG_PARAMETER); + ACE_CHECK; +} + #if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) template class TAO_ESF_Shutdown_Proxy<TAO_Notify_Proxy>; diff --git a/TAO/orbsvcs/orbsvcs/Notify/Admin.h b/TAO/orbsvcs/orbsvcs/Notify/Admin.h index c2c384df821..592c8481560 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Admin.h +++ b/TAO/orbsvcs/orbsvcs/Notify/Admin.h @@ -22,7 +22,7 @@ #include "FilterAdmin.h" #include "EventTypeSeq.h" -#include "Object.h" +#include "Topology_Object.h" class TAO_Notify_Proxy; class TAO_Notify_EventChannel; @@ -35,7 +35,7 @@ template <class TYPE> class TAO_Notify_Container_T; * */ -class TAO_Notify_Serv_Export TAO_Notify_Admin : public virtual TAO_Notify_Object +class TAO_Notify_Serv_Export TAO_Notify_Admin : public TAO_NOTIFY::Topology_Parent { friend class TAO_Notify_Builder; public: @@ -43,7 +43,7 @@ public: typedef CosNotifyChannelAdmin::AdminIDSeq_var SEQ_VAR; /// Constuctor - TAO_Notify_Admin (void); + TAO_Notify_Admin (); /// Destructor ~TAO_Notify_Admin (); @@ -69,14 +69,27 @@ public: CosNotifyChannelAdmin::InterFilterGroupOperator filter_operator (void); /// Obtain the Admin's subscribed types. - void subscribed_types (TAO_Notify_EventTypeSeq& subscribed_types + void subscribed_types (TAO_Notify_EventTypeSeq& subscribed_types ACE_ENV_ARG_DECL); /// Shutdown virtual int shutdown (ACE_ENV_SINGLE_ARG_DECL); + virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL); + virtual TAO_NOTIFY::Topology_Object* load_child (const ACE_CString &type, + CORBA::Long id, const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL); + virtual void reconnect (ACE_ENV_SINGLE_ARG_DECL); + + void set_default (bool is_default); + bool is_default () const; + virtual void load_attrs(const TAO_NOTIFY::NVPList& attrs); + protected: - typedef TAO_Notify_Container_T <TAO_Notify_Proxy> + void save_attrs (TAO_NOTIFY::NVPList& attrs); + virtual const char * get_admin_type_name (void) const = 0; + +protected: + typedef TAO_Notify_Container_T <TAO_Notify_Proxy> TAO_Notify_Proxy_Container; /// = Data Members @@ -95,6 +108,8 @@ protected: /// Filter operator CosNotifyChannelAdmin::InterFilterGroupOperator filter_operator_; + + bool is_default_; }; #if defined (__ACE_INLINE__) diff --git a/TAO/orbsvcs/orbsvcs/Notify/Admin.inl b/TAO/orbsvcs/orbsvcs/Notify/Admin.inl index 8b6d8641eeb..155f2743b5b 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Admin.inl +++ b/TAO/orbsvcs/orbsvcs/Notify/Admin.inl @@ -17,3 +17,17 @@ TAO_Notify_Admin::filter_operator (void) { return this->filter_operator_; } + +ACE_INLINE +void +TAO_Notify_Admin::set_default (bool is_default) +{ + this->is_default_ = is_default; +} + +ACE_INLINE +bool +TAO_Notify_Admin::is_default (void) const +{ + return this->is_default_; +} diff --git a/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.cpp b/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.cpp index 1d373b8eac8..1c90b0e5248 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.cpp @@ -6,8 +6,8 @@ #include "AdminProperties.inl" #endif /* __ACE_INLINE__ */ -ACE_RCSID (Notify, - TAO_Notify_AdminProperties, +ACE_RCSID (Notify, + TAO_Notify_AdminProperties, "$Id$") #include "orbsvcs/CosNotificationC.h" @@ -43,6 +43,38 @@ TAO_Notify_AdminProperties::init (const CosNotification::PropertySeq& prop_seq) return 0; } +void +TAO_Notify_AdminProperties::init () +{ + // This method should only be called once, (during topo load) + ACE_ASSERT(this->size() == 0); + + if (this->max_global_queue_length_.is_valid()) + { + CORBA::Any a; + a <<= this->max_global_queue_length_.value(); + this->add(this->max_global_queue_length_.name(), a); + } + if (this->max_consumers_.is_valid()) + { + CORBA::Any a; + a <<= this->max_consumers_.value(); + this->add(this->max_consumers_.name(), a); + } + if (this->max_suppliers_.is_valid()) + { + CORBA::Any a; + a <<= this->max_suppliers_.value(); + this->add(this->max_suppliers_.name(), a); + } + if (this->reject_new_events_.is_valid()) + { + CORBA::Any a; + a <<= CORBA::Any::from_boolean(this->reject_new_events_.value()); + this->add(this->reject_new_events_.name(), a); + } +} + CORBA::Boolean TAO_Notify_AdminProperties::queue_full (void) { diff --git a/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.h b/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.h index e7f51ebc5a0..5594add39b6 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.h +++ b/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.h @@ -37,7 +37,7 @@ * @brief The AdminProperties per EventChannel. * */ -class TAO_Notify_Serv_Export TAO_Notify_AdminProperties +class TAO_Notify_Serv_Export TAO_Notify_AdminProperties : public TAO_Notify_PropertySeq { public: @@ -50,12 +50,21 @@ public: // Init int init (const CosNotification::PropertySeq& prop_seq); - // = Accessors + // finish initialization after values are set by topology load + void init (); + + // = Const Accessors const TAO_Notify_Property_Long& max_global_queue_length (void) const; const TAO_Notify_Property_Long& max_consumers (void) const; const TAO_Notify_Property_Long& max_suppliers (void) const; const TAO_Notify_Property_Boolean& reject_new_events (void) const; + // = Non-const accessors + TAO_Notify_Property_Long & max_global_queue_length (void); + TAO_Notify_Property_Long & max_consumers (void); + TAO_Notify_Property_Long & max_suppliers (void); + TAO_Notify_Property_Boolean & reject_new_events (void); + CORBA::Long& global_queue_length (void); TAO_SYNCH_MUTEX& global_queue_lock (void); TAO_SYNCH_CONDITION& global_queue_not_full_condition (void); @@ -109,8 +118,8 @@ protected: TAO_Notify_Atomic_Property_Long suppliers_; }; -typedef ACE_Refcounted_Auto_Ptr<TAO_Notify_AdminProperties, - TAO_SYNCH_MUTEX> +typedef ACE_Refcounted_Auto_Ptr<TAO_Notify_AdminProperties, + TAO_SYNCH_MUTEX> TAO_Notify_AdminProperties_var; #if defined (__ACE_INLINE__) diff --git a/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.inl b/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.inl index 0eea011af97..36743cc9dc1 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.inl +++ b/TAO/orbsvcs/orbsvcs/Notify/AdminProperties.inl @@ -6,24 +6,48 @@ TAO_Notify_AdminProperties::max_global_queue_length (void) const return this->max_global_queue_length_; } +ACE_INLINE TAO_Notify_Property_Long& +TAO_Notify_AdminProperties::max_global_queue_length (void) +{ + return this->max_global_queue_length_; +} + ACE_INLINE const TAO_Notify_Property_Long& TAO_Notify_AdminProperties::max_consumers (void) const { return this->max_consumers_; } +ACE_INLINE TAO_Notify_Property_Long& +TAO_Notify_AdminProperties::max_consumers (void) +{ + return this->max_consumers_; +} + ACE_INLINE const TAO_Notify_Property_Long& TAO_Notify_AdminProperties::max_suppliers (void) const { return this->max_suppliers_; } +ACE_INLINE TAO_Notify_Property_Long& +TAO_Notify_AdminProperties::max_suppliers (void) +{ + return this->max_suppliers_; +} + ACE_INLINE const TAO_Notify_Property_Boolean& TAO_Notify_AdminProperties::reject_new_events (void) const { return this->reject_new_events_; } +ACE_INLINE TAO_Notify_Property_Boolean& +TAO_Notify_AdminProperties::reject_new_events (void) +{ + return this->reject_new_events_; +} + ACE_INLINE CORBA::Long& TAO_Notify_AdminProperties::global_queue_length (void) { diff --git a/TAO/orbsvcs/orbsvcs/Notify/AllocTracker.h b/TAO/orbsvcs/orbsvcs/Notify/AllocTracker.h new file mode 100644 index 00000000000..5568ce5e720 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/AllocTracker.h @@ -0,0 +1,81 @@ +// $Id$ +#ifndef ALLOC_TRACKER_H +#define ALLOC_TRACKER_H +#include /**/"ace/pre.h" + +#include "notify_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +//#define DEBUG_MEMORY_USE +#if defined(_MSC_VER) && defined (_DEBUG) && defined (DEBUG_MEMORY_USE) +namespace CRT{ + +/// \brief dump heap allocation stats +/// +/// This works only on microsoft/windows compilers +/// but it's handy to diagnose memory allocation problems. +/// To use, add the following macro in the scope where you +/// want to check memory usage. +/// ACE_WIN32_HEAP_MONITOR(name); +/// where name is a quoted string to label the stats. +/// When the object created by this macro goes out of scope +/// it will write a log message like: +/// (10056|6396) name: New heap blocks: 39; bytes: 19550 +/// +/// For non-debug, or non-vc builds, the macro expands to nothing +class CrtHeapDumper +{ +public: + CrtHeapDumper(const char * name, bool verbose = false) + : name_ (name) + , verbose_ (verbose) + { + _CrtMemCheckpoint (&before_); + } + + ~CrtHeapDumper() + { + dump(); + } + void dump() + { + _CrtMemState after; + _CrtMemCheckpoint (&after); + _CrtMemState diff; + _CrtMemDifference (&diff, &before_, &after); + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) %s: New heap blocks: %d; bytes: %d\n"), + name_.c_str (), + ACE_static_cast (int, diff.lCounts[_NORMAL_BLOCK]), + ACE_static_cast (int, diff.lSizes[_NORMAL_BLOCK]) + )); + if (this->verbose_) + { + _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT ); + _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT ); + _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT ); + _CrtMemDumpAllObjectsSince (&this->before_); + } + } + +private: + ACE_CString name_; + bool verbose_; + _CrtMemState before_; +}; +} //namespace +#define ACE_WIN32_HEAP_MONITOR(name) \ + CrtHeapDumper heap_check___(name); \ + ACE_UNUSED_ARG (heap_check___) +#else // _MSC_VER etc + #define ACE_WIN32_HEAP_MONITOR(name) +#endif // _MSC_VER etc +#include /**/"ace/post.h" +#endif // ALLOC_TRACKER_H diff --git a/TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.cpp b/TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.cpp new file mode 100644 index 00000000000..1c4ebf58906 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.cpp @@ -0,0 +1,118 @@ +// $Id$ + +#include "Bit_Vector.h" + +namespace TAO_NOTIFY +{ + +Bit_Vector::Bit_Vector() + : size_(0) + , first_set_bit_(0) + , first_cleared_bit_(0) +{ +} + +Bit_Vector::~Bit_Vector() +{ +} + +bool +Bit_Vector::is_set(const size_t location) const +{ + bool result = false; + if (location < this->size_) + { + result = (0 != (this->bitvec_[location >> BPW_LOG_2] & (1 << (location % BITS_PER_WORD)))); + } + return result; +} + +void +Bit_Vector::set_bit(const size_t location, bool set) +{ + if (location >= this->size_) + { + if ((location >> BPW_LOG_2) >= (this->size_ >> BPW_LOG_2)) + { + size_t need = (location >> BPW_LOG_2) - (this->size_ >> BPW_LOG_2); + this->bitvec_.resize(this->bitvec_.size() + need + 1, 0); + } + this->size_ = location + 1; + } + if (set) + { + this->bitvec_[location >> BPW_LOG_2] |= (1 << (location % BITS_PER_WORD)); + } + else + { + this->bitvec_[location >> BPW_LOG_2] &= ~(1 << (location % BITS_PER_WORD)); + } + this->evaluate_firsts(location, set); +} + +size_t +Bit_Vector::find_first_bit(bool set) const +{ + size_t result = 0; + if (set) + { + result = this->first_set_bit_; + } + else + { + result = this->first_cleared_bit_; + } + return result; +} + +void +Bit_Vector::evaluate_firsts(const size_t location, bool set) +{ + if (set) + { + if (this->first_cleared_bit_ == location) + { + this->first_cleared_bit_ = this->find_first_bit_of(location, false); + } + if (this->first_set_bit_ > location) + { + this->first_set_bit_ = location; + } + } + else if (!set) + { + if (this->first_set_bit_ == location) + { + this->first_set_bit_ = this->find_first_bit_of(location, true); + } + if (this->first_cleared_bit_ > location) + { + this->first_cleared_bit_ = location; + } + } +} + +size_t +Bit_Vector::find_first_bit_of(const size_t location, bool set) +{ + size_t newloc = 0; + size_t idx = 0; + for (idx = location; (newloc == 0) && (idx < this->size_ + 1); idx++) + { + if (is_set(idx) == set) + { + newloc = idx; + } + } + return newloc; +} + +} + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +template class ACE_Vector<ACE_UINT32>; +template class ACE_Array_Base<ACE_UINT32>; +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#pragma instantiate ACE_Vector<ACE_UINT32> +#pragma instantiate ACE_Array_Base<ACE_UINT32> +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.h b/TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.h new file mode 100644 index 00000000000..eb143b45e38 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Bit_Vector.h @@ -0,0 +1,76 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Bit_Vector.h + * + * $Id$ + * + * This is a basic bit vector class. + * + * @author Jonathan Pollack <pollack_j@ociweb.com> + */ +//============================================================================= + +#ifndef BIT_VECTOR_H +#define BIT_VECTOR_H +#include /**/ "ace/pre.h" +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "notify_export.h" + +#include "ace/Vector_T.h" +#include "ace/Basic_Types.h" + +namespace TAO_NOTIFY +{ + +/// \brief Simple bit vector. +/// +/// Written to support block allocation from persistent storage. +/// Should be promoted to the ACE level to make it generally usable. +class TAO_Notify_Export Bit_Vector +{ + typedef ACE_UINT32 BASIC_UINT_TYPE; + typedef ACE_Vector<BASIC_UINT_TYPE> VECTOR_TYPE; + enum { + BITS_PER_WORD = 32, + BPW_LOG_2 = 5 + }; +public: + + /// The constructor. + Bit_Vector(); + /// The destructor. + ~Bit_Vector(); + + /// \brief Determine if a bit at location is set. + bool is_set(const size_t location) const; + /// \brief Set or unset a bit at location, growing the vector as needed. + void set_bit(const size_t location, bool set); + + /// \brief Find the first bit that is either set or unset in an O(1). + size_t find_first_bit(bool set) const; + +private: + /// Update our first set and unset bits. + void evaluate_firsts(const size_t location, bool set); + /// Iterate from location to the end, finding the first bit that + /// matches the requested set or unset value. + size_t find_first_bit_of(const size_t location, bool set); + +private: + VECTOR_TYPE bitvec_; + size_t size_; + size_t first_set_bit_; + size_t first_cleared_bit_; +}; + +} + +#include /**/ "ace/post.h" +#endif /* BIT_VECTOR_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Builder.cpp b/TAO/orbsvcs/orbsvcs/Notify/Builder.cpp index be7c6fafeba..1c185e7dd4a 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Builder.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/Builder.cpp @@ -5,8 +5,8 @@ #include "Builder.inl" #endif /* __ACE_INLINE__ */ -ACE_RCSID (Notify, - Builder, +ACE_RCSID (Notify, + Builder, "$Id$") #include "ace/Dynamic_Service.h" @@ -41,10 +41,10 @@ ACE_RCSID (Notify, #include "ETCL_FilterFactory.h" #include "Container_T.h" -template <class PROXY_IMPL, - class PROXY, - class PROXY_PTR, - class PROXY_VAR, +template <class PROXY_IMPL, + class PROXY, + class PROXY_PTR, + class PROXY_VAR, class PARENT> class TAO_Notify_Proxy_Builder_T { @@ -83,6 +83,32 @@ public: return proxy_ret._retn (); } + + PROXY_IMPL* + build (PARENT *parent, const CosNotifyChannelAdmin::ProxyID proxy_id + ACE_ENV_ARG_DECL) + { + TAO_Notify_Factory* factory = TAO_Notify_PROPERTIES::instance ()->factory (); + + PROXY_IMPL* proxy = 0; + factory->create (proxy ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + PortableServer::ServantBase_var servant (proxy); + + proxy->init (parent ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + proxy->activate (proxy, proxy_id ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + // insert proxy in admin container. + parent->insert (proxy ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + return proxy; + } + }; // define the ProxyConsumer Builders. @@ -183,7 +209,7 @@ TAO_Notify_Builder::build_event_channel_factory (PortableServer::POA_ptr poa ACE factory->create (ecf ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (ecf_ret._retn ()); - PortableServer::ServantBase_var servant_var (ecf); +// PortableServer::ServantBase_var servant_var (ecf); ecf->TAO_Notify_EventChannelFactory::init (poa ACE_ENV_ARG_PARAMETER); @@ -197,7 +223,11 @@ TAO_Notify_Builder::build_event_channel_factory (PortableServer::POA_ptr poa ACE } CosNotifyChannelAdmin::EventChannel_ptr -TAO_Notify_Builder::build_event_channel (TAO_Notify_EventChannelFactory* ecf, const CosNotification::QoSProperties & initial_qos, const CosNotification::AdminProperties & initial_admin, CosNotifyChannelAdmin::ChannelID_out id ACE_ENV_ARG_DECL) +TAO_Notify_Builder::build_event_channel ( + TAO_Notify_EventChannelFactory* ecf, + const CosNotification::QoSProperties & initial_qos, + const CosNotification::AdminProperties & initial_admin, + CosNotifyChannelAdmin::ChannelID_out id ACE_ENV_ARG_DECL) { CosNotifyChannelAdmin::EventChannel_var ec_ret; @@ -207,7 +237,7 @@ TAO_Notify_Builder::build_event_channel (TAO_Notify_EventChannelFactory* ecf, co factory->create (ec ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (ec_ret._retn ()); - PortableServer::ServantBase_var servant_var (ec); +// PortableServer::ServantBase_var servant_var (ec); ec->init (ecf, initial_qos, initial_admin ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (ec_ret._retn ()); @@ -228,8 +258,35 @@ TAO_Notify_Builder::build_event_channel (TAO_Notify_EventChannelFactory* ecf, co return ec_ret._retn (); } +TAO_Notify_EventChannel * +TAO_Notify_Builder::build_event_channel ( + TAO_Notify_EventChannelFactory* ecf, + const CosNotifyChannelAdmin::ChannelID id ACE_ENV_ARG_DECL) +{ + TAO_Notify_Factory* factory = TAO_Notify_PROPERTIES::instance ()->factory (); + + TAO_Notify_EventChannel* ec = 0; + factory->create (ec ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + ec->init (ecf ACE_ENV_ARG_PARAMETER); //, initial_qos, initial_admin + ACE_CHECK_RETURN (0); + + // insert ec in ec container. + ecf->ec_container_->insert (ec ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + ec->activate (ec, id ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + return ec; +} + CosNotifyChannelAdmin::ConsumerAdmin_ptr -TAO_Notify_Builder::build_consumer_admin (TAO_Notify_EventChannel* ec, CosNotifyChannelAdmin::InterFilterGroupOperator op, CosNotifyChannelAdmin::AdminID_out id ACE_ENV_ARG_DECL) +TAO_Notify_Builder::build_consumer_admin ( + TAO_Notify_EventChannel* ec, + CosNotifyChannelAdmin::InterFilterGroupOperator op, + CosNotifyChannelAdmin::AdminID_out id ACE_ENV_ARG_DECL) { CosNotifyChannelAdmin::ConsumerAdmin_var ca_ret; @@ -239,7 +296,7 @@ TAO_Notify_Builder::build_consumer_admin (TAO_Notify_EventChannel* ec, CosNotify factory->create (ca ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (ca_ret._retn ()); - PortableServer::ServantBase_var servant_var (ca); +// PortableServer::ServantBase_var servant_var (ca); ca->init (ec ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (ca_ret._retn ()); @@ -261,6 +318,31 @@ TAO_Notify_Builder::build_consumer_admin (TAO_Notify_EventChannel* ec, CosNotify return ca_ret._retn (); } +TAO_Notify_ConsumerAdmin * +TAO_Notify_Builder::build_consumer_admin ( + TAO_Notify_EventChannel* ec, + const CosNotifyChannelAdmin::ChannelID id + ACE_ENV_ARG_DECL) +{ + TAO_Notify_Factory* factory = TAO_Notify_PROPERTIES::instance ()->factory (); + TAO_Notify_ConsumerAdmin * ca = 0; + factory->create (ca ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + +// PortableServer::ServantBase_var servant_var (ca); + + ca->init (ec ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + CORBA::Object_var obj = ca->activate (ca, id ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + // insert admin in CA container. + ec->ca_container_->insert (ca ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + return ca; +} + CosNotifyChannelAdmin::SupplierAdmin_ptr TAO_Notify_Builder::build_supplier_admin (TAO_Notify_EventChannel* ec, CosNotifyChannelAdmin::InterFilterGroupOperator op, CosNotifyChannelAdmin::AdminID_out id ACE_ENV_ARG_DECL) { @@ -272,7 +354,7 @@ TAO_Notify_Builder::build_supplier_admin (TAO_Notify_EventChannel* ec, CosNotify factory->create (sa ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (sa_ret._retn ()); - PortableServer::ServantBase_var servant_var (sa); +// PortableServer::ServantBase_var servant_var (sa); sa->init (ec ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (sa_ret._retn ()); @@ -294,6 +376,32 @@ TAO_Notify_Builder::build_supplier_admin (TAO_Notify_EventChannel* ec, CosNotify return sa_ret._retn (); } +TAO_Notify_SupplierAdmin * +TAO_Notify_Builder::build_supplier_admin ( + TAO_Notify_EventChannel* ec, + const CosNotifyChannelAdmin::ChannelID id + ACE_ENV_ARG_DECL) +{ + TAO_Notify_Factory* factory = TAO_Notify_PROPERTIES::instance ()->factory (); + TAO_Notify_SupplierAdmin * sa = 0; + factory->create (sa ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + +// PortableServer::ServantBase_var servant_var (ca); + + sa->init (ec ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + CORBA::Object_var obj = sa->activate (sa, id ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + // insert admin in CA container. + ec->sa_container_->insert (sa ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + return sa; +} + CosNotifyChannelAdmin::ProxyConsumer_ptr TAO_Notify_Builder::build_proxy(TAO_Notify_SupplierAdmin* sa , CosNotifyChannelAdmin::ClientType ctype @@ -366,6 +474,76 @@ TAO_Notify_Builder::build_proxy(TAO_Notify_ConsumerAdmin* ca } } +TAO_Notify_ProxyConsumer * +TAO_Notify_Builder::build_proxy(TAO_Notify_SupplierAdmin* sa + , CosNotifyChannelAdmin::ClientType ctype + , const CosNotifyChannelAdmin::ProxyID proxy_id + ACE_ENV_ARG_DECL) +{ + switch (ctype) + { + case CosNotifyChannelAdmin::ANY_EVENT: + { + TAO_Notify_ProxyPushConsumer_Builder pb; + return pb.build (sa, proxy_id ACE_ENV_ARG_PARAMETER); + } + break; + + case CosNotifyChannelAdmin::STRUCTURED_EVENT: + { + TAO_Notify_StructuredProxyPushConsumer_Builder pb; + return pb.build (sa, proxy_id ACE_ENV_ARG_PARAMETER); + } + break; + + case CosNotifyChannelAdmin::SEQUENCE_EVENT: + { + TAO_Notify_SequenceProxyPushConsumer_Builder pb; + return pb.build (sa, proxy_id ACE_ENV_ARG_PARAMETER); + } + break; + + default: + ACE_THROW_RETURN (CORBA::BAD_PARAM (), + 0); + } +} + +TAO_Notify_ProxySupplier * +TAO_Notify_Builder::build_proxy(TAO_Notify_ConsumerAdmin* ca + , CosNotifyChannelAdmin::ClientType ctype + , const CosNotifyChannelAdmin::ProxyID proxy_id + ACE_ENV_ARG_DECL) +{ + switch (ctype) + { + case CosNotifyChannelAdmin::ANY_EVENT: + { + TAO_Notify_ProxyPushSupplier_Builder pb; + return pb.build (ca, proxy_id ACE_ENV_ARG_PARAMETER); + } + break; + + case CosNotifyChannelAdmin::STRUCTURED_EVENT: + { + TAO_Notify_StructuredProxyPushSupplier_Builder pb; + return pb.build (ca, proxy_id ACE_ENV_ARG_PARAMETER); + } + break; + + case CosNotifyChannelAdmin::SEQUENCE_EVENT: + { + TAO_Notify_SequenceProxyPushSupplier_Builder pb; + return pb.build (ca, proxy_id ACE_ENV_ARG_PARAMETER); + } + break; + + default: + ACE_THROW_RETURN (CORBA::BAD_PARAM (), + 0); + } +} + CosEventChannelAdmin::ProxyPushSupplier_ptr TAO_Notify_Builder::build_proxy (TAO_Notify_ConsumerAdmin* ca ACE_ENV_ARG_DECL) { diff --git a/TAO/orbsvcs/orbsvcs/Notify/Builder.h b/TAO/orbsvcs/orbsvcs/Notify/Builder.h index bcf5abd6bec..7dbce8fad0a 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Builder.h +++ b/TAO/orbsvcs/orbsvcs/Notify/Builder.h @@ -26,6 +26,7 @@ #include "orbsvcs/NotifyExtC.h" #include "AdminProperties.h" +#include "Topology_Object.h" class TAO_Notify_EventChannelFactory; class TAO_Notify_EventChannel; @@ -66,6 +67,13 @@ public: , CosNotifyChannelAdmin::ChannelID_out id ACE_ENV_ARG_DECL); + + virtual TAO_Notify_EventChannel * + build_event_channel (TAO_Notify_EventChannelFactory* ecf + , const CosNotifyChannelAdmin::ChannelID id + ACE_ENV_ARG_DECL); + + /// Build ConsumerAdmin virtual CosNotifyChannelAdmin::ConsumerAdmin_ptr build_consumer_admin (TAO_Notify_EventChannel* ec @@ -73,13 +81,31 @@ public: , CosNotifyChannelAdmin::AdminID_out id ACE_ENV_ARG_DECL); + /// Build ConsumerAdmin during topology restore + /// TODO: this returns a reference to the actual type + /// to accomodate loadable builder/factory there should + /// be an appropriate base class for it to return. + virtual TAO_Notify_ConsumerAdmin * + build_consumer_admin (TAO_Notify_EventChannel* ec + , const CosNotifyChannelAdmin::AdminID id //CORBA::Long id // note: an in parameter! + ACE_ENV_ARG_DECL); + /// Build SupplierAdmin virtual CosNotifyChannelAdmin::SupplierAdmin_ptr - build_supplier_admin (TAO_Notify_EventChannel* ec + build_supplier_admin (TAO_Notify_EventChannel * ec , CosNotifyChannelAdmin::InterFilterGroupOperator op , CosNotifyChannelAdmin::AdminID_out id ACE_ENV_ARG_DECL); + /// Build ConsumerAdmin during topology restore + /// TODO: this returns a reference to the actual type + /// to accomodate loadable builder/factory there should + /// be an appropriate base class for it to return. + virtual TAO_Notify_SupplierAdmin * + build_supplier_admin (TAO_Notify_EventChannel * ec + , const CosNotifyChannelAdmin::AdminID id //CORBA::Long id // note: an in parameter! + ACE_ENV_ARG_DECL); + /// Build ProxyConsumer virtual CosNotifyChannelAdmin::ProxyConsumer_ptr build_proxy (TAO_Notify_SupplierAdmin* sa @@ -88,6 +114,13 @@ public: , const CosNotification::QoSProperties & initial_qos ACE_ENV_ARG_DECL); + /// Reload ProxyConsumer + virtual TAO_Notify_ProxyConsumer * + build_proxy (TAO_Notify_SupplierAdmin* sa + , CosNotifyChannelAdmin::ClientType ctype + , const CosNotifyChannelAdmin::ProxyID proxy_id + ACE_ENV_ARG_DECL); + /// Build ProxySupplier. virtual CosNotifyChannelAdmin::ProxySupplier_ptr build_proxy (TAO_Notify_ConsumerAdmin* ca @@ -96,6 +129,13 @@ public: , const CosNotification::QoSProperties & initial_qos ACE_ENV_ARG_DECL); + /// Reload ProxySupplier. + virtual TAO_Notify_ProxySupplier * + build_proxy (TAO_Notify_ConsumerAdmin* ca + , CosNotifyChannelAdmin::ClientType ctype + , const CosNotifyChannelAdmin::ProxyID proxy_id + ACE_ENV_ARG_DECL); + /// Build CosEC style ProxySupplier. virtual CosEventChannelAdmin::ProxyPushSupplier_ptr build_proxy (TAO_Notify_ConsumerAdmin* ca ACE_ENV_ARG_DECL); @@ -111,15 +151,15 @@ public: /// Apply Thread Pools. virtual void apply_thread_pool_concurrency ( - TAO_Notify_Object& object, - const NotifyExt::ThreadPoolParams& tp_params + TAO_Notify_Object& object, + const NotifyExt::ThreadPoolParams& tp_params ACE_ENV_ARG_DECL ); /// Apply Thread Pools with Lanes. virtual void apply_lane_concurrency ( - TAO_Notify_Object& object, - const NotifyExt::ThreadPoolLanesParams& tpl_params + TAO_Notify_Object& object, + const NotifyExt::ThreadPoolLanesParams& tpl_params ACE_ENV_ARG_DECL ); }; diff --git a/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.cpp b/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.cpp index 5552b0df58b..762b6be2c95 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.cpp @@ -6,8 +6,8 @@ #include "ConsumerAdmin.inl" #endif /* __ACE_INLINE__ */ -ACE_RCSID (RT_Notify, - TAO_Notify_ConsumerAdmin, +ACE_RCSID (RT_Notify, + TAO_Notify_ConsumerAdmin, "$Id$") #include "ace/Auto_Ptr.h" @@ -20,6 +20,11 @@ ACE_RCSID (RT_Notify, #include "Builder.h" #include "Find_Worker_T.h" #include "Seq_Worker_T.h" +#include "ProxySupplier.h" + +#include "tao/debug.h" +//#define DEBUG_LEVEL 9 +#define DEBUG_LEVEL TAO_debug_level typedef TAO_Notify_Find_Worker_T<TAO_Notify_Proxy , CosNotifyChannelAdmin::ProxySupplier @@ -30,9 +35,18 @@ TAO_Notify_ProxySupplier_Find_Worker; typedef TAO_Notify_Seq_Worker_T<TAO_Notify_Proxy> TAO_Notify_Proxy_Seq_Worker; TAO_Notify_ConsumerAdmin::TAO_Notify_ConsumerAdmin (void) + : TAO_Notify_Admin () +{ +} + +const char * +TAO_Notify_ConsumerAdmin::get_admin_type_name () const { + return "consumer_admin"; } + + TAO_Notify_ConsumerAdmin::~TAO_Notify_ConsumerAdmin () { } @@ -83,6 +97,76 @@ TAO_Notify_ConsumerAdmin::destroy (ACE_ENV_SINGLE_ARG_DECL) ACE_CHECK; } + +TAO_NOTIFY::Topology_Object* +TAO_Notify_ConsumerAdmin::load_child (const ACE_CString &type, + CORBA::Long id, const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL) +{ + TAO_NOTIFY::Topology_Object* result = this; + if (type == "proxy_push_supplier") + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Admin reload proxy %d\n") + , ACE_static_cast (int, id) + )); + result = this->load_proxy(id, CosNotifyChannelAdmin::ANY_EVENT, attrs ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } + else if (type == "structured_proxy_push_supplier") + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Admin reload proxy %d\n") + , ACE_static_cast (int, id) + )); + result = this->load_proxy(id, CosNotifyChannelAdmin::STRUCTURED_EVENT, attrs ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } + else if (type == "sequence_proxy_push_supplier") + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Admin reload proxy %d\n") + , ACE_static_cast (int, id) + )); + result = this->load_proxy(id, CosNotifyChannelAdmin::SEQUENCE_EVENT, attrs ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } +#if 0 + else if (type == "ec_proxy_push_supplier") + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Admin reload proxy %d\n") + , ACE_static_cast (int, id) + )); + result = this->load_proxy(id, attrs ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } +#endif + else + { + result = TAO_Notify_Admin::load_child (type, id, attrs ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } + return result; +} + +TAO_NOTIFY::Topology_Object* +TAO_Notify_ConsumerAdmin::load_proxy ( + CORBA::Long id, + CosNotifyChannelAdmin::ClientType ctype, + const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL) +{ + TAO_Notify_Builder* bld = TAO_Notify_PROPERTIES::instance()->builder(); + TAO_Notify_ProxySupplier * proxy = + bld->build_proxy (this + , ctype + , id + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + ACE_ASSERT(proxy != 0); + proxy->load_attrs (attrs); + return proxy; +} + CosNotifyChannelAdmin::ProxySupplier_ptr TAO_Notify_ConsumerAdmin::obtain_notification_push_supplier (CosNotifyChannelAdmin::ClientType ctype, CosNotifyChannelAdmin::ProxyID_out proxy_id @@ -95,11 +179,16 @@ TAO_Notify_ConsumerAdmin::obtain_notification_push_supplier (CosNotifyChannelAdm { CosNotification::QoSProperties initial_qos; - return TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this + CosNotifyChannelAdmin::ProxySupplier_var proxy = + TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this , ctype , proxy_id - , initial_qos + , initial_qos ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (proxy._retn ()); + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (proxy._retn ()); + return proxy._retn (); } CosNotifyChannelAdmin::ProxySupplier_ptr @@ -114,11 +203,16 @@ TAO_Notify_ConsumerAdmin::obtain_notification_push_supplier_with_qos (CosNotifyC , CosNotification::UnsupportedQoS )) { - return TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this + CosNotifyChannelAdmin::ProxySupplier_var proxy = + TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this , ctype , proxy_id , initial_qos ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (proxy._retn ()); + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (proxy._retn ()); + return proxy._retn (); } CosEventChannelAdmin::ProxyPushSupplier_ptr @@ -127,7 +221,12 @@ TAO_Notify_ConsumerAdmin::obtain_push_supplier (ACE_ENV_SINGLE_ARG_DECL) CORBA::SystemException )) { - return TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this ACE_ENV_ARG_PARAMETER); + CosEventChannelAdmin::ProxyPushSupplier_var proxy = + TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (proxy._retn ()); + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (proxy._retn ()); + return proxy._retn (); } CosNotifyChannelAdmin::AdminID @@ -223,6 +322,7 @@ TAO_Notify_ConsumerAdmin::subscription_change (const CosNotification::EventTypeS this->proxy_container_->collection()->for_each (&worker ACE_ENV_ARG_PARAMETER); } + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); } CosNotifyFilter::FilterID @@ -231,7 +331,12 @@ TAO_Notify_ConsumerAdmin::add_filter (CosNotifyFilter::Filter_ptr new_filter ACE CORBA::SystemException )) { - return this->filter_admin_.add_filter (new_filter ACE_ENV_ARG_PARAMETER); + CosNotifyFilter::FilterID fid = + this->filter_admin_.add_filter (new_filter ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (fid); + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (fid); + return fid; } void diff --git a/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.h b/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.h index 99964a7cd11..880129fd4e1 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.h +++ b/TAO/orbsvcs/orbsvcs/Notify/ConsumerAdmin.h @@ -57,7 +57,20 @@ public: /// Release this object. virtual void release (void); + virtual const char * get_admin_type_name () const; + + virtual TAO_NOTIFY::Topology_Object* load_child ( + const ACE_CString &type, + CORBA::Long id, + const TAO_NOTIFY::NVPList& attrs + ACE_ENV_ARG_DECL); + protected: + TAO_NOTIFY::Topology_Object *load_proxy ( + CORBA::Long id, + CosNotifyChannelAdmin::ClientType ctype, + const TAO_NOTIFY::NVPList& attrs + ACE_ENV_ARG_DECL); /// = NotifyExt::ConsumerAdmin methods virtual CosNotifyChannelAdmin::ProxySupplier_ptr diff --git a/TAO/orbsvcs/orbsvcs/Notify/CosNotify_Service.cpp b/TAO/orbsvcs/orbsvcs/Notify/CosNotify_Service.cpp index 4fcfbe8081e..da6c7459da9 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/CosNotify_Service.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/CosNotify_Service.cpp @@ -104,6 +104,11 @@ TAO_CosNotify_Service::init (int argc, char *argv[]) task_per_proxy = 1; arg_shifter.consume_arg (); } + else if (arg_shifter.cur_arg_strncasecmp (ACE_LIB_TEXT("-AllowReconnect")) == 0) + { + arg_shifter.consume_arg (); + TAO_Notify_PROPERTIES::instance()->allow_reconnect (true); + } } // Init the EC QoS diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.cpp b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.cpp new file mode 100644 index 00000000000..26191c7920c --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.cpp @@ -0,0 +1,80 @@ +// $Id$ + +#include "Delivery_Method.h" + +#if ! defined (__ACE_INLINE__) +#include "Delivery_Method.inl" +#endif /* __ACE_INLINE__ */ + +#include "orbsvcs/Time_Utilities.h" +#include "tao/debug.h" +#include "ace/OS_NS_sys_time.h" + +//#define DEBUG_LEVEL 9 +#define DEBUG_LEVEL TAO_debug_level + +ACE_RCSID(RT_Notify, TAO_Notify_Method_Request, "$Id$") + +namespace TAO_NOTIFY +{ + +////////////////// +// Delivery Method +Delivery_Method::Delivery_Method (const TAO_NOTIFY::Delivery_Request_Ptr & delivery_request) + : TAO_Notify_Method_Request () + , delivery_request_ (delivery_request) +{ + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Delivery Method: constructor\n") + )); + // Set the parameters that affect queuing in the message queue. + // The ACE_Message_Block priorities go from 0 (lowest) to ULONG_MAX + // (highest), while the Notification Events go from -32767 (lowest, + // even though CORBA::Short goes to -32768) to 32767 (highest). + + // Convert to CORBA::Long to preserve the sign. Conversion to + // unsigned long will happen automatically and we do not have to worry + // about losing the number in the addition since priority () returns a + // CORBA::Short. + const TAO_Notify_Event_Ptr pevent = this->delivery_request_->event (); + this->msg_priority ((CORBA::Long)pevent->priority ().value () + + PRIORITY_BASE); + + // The deadline time for the message block is absolute, while the + // timeout for the event is relative to the time it was received. + // So, we do a little conversion and set it on the message block (us) + + TAO_Notify_Property_Time& timeout = pevent->timeout (); + + if (timeout.is_valid () && timeout.value() != 0) + { + ACE_Time_Value tv = ACE_OS::gettimeofday(); + tv += ORBSVCS_Time::to_Time_Value(timeout.value()); + this->msg_deadline_time (tv); + } +} + +Delivery_Method::Delivery_Method (const Delivery_Method & rhs) + : TAO_Notify_Method_Request () + , delivery_request_ (rhs.delivery_request_) +{ +} + +Delivery_Method::~Delivery_Method () +{ + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Delivery Method: destructor\n") + )); +} + +const TAO_Notify_Event& +Delivery_Method::event (void) const +{ + return * this->delivery_request_->event (); +} + +} //namespace TAO_NOTIFY + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#endif /*ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.h b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.h new file mode 100644 index 00000000000..d5f43275eac --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method.h @@ -0,0 +1,78 @@ +/* -*- C++ -*- */ +/** + * @file Delivery_Method.h + * + * $Id$ + * + * + */ + +#ifndef TAO_NOTIFY_DELIVERY_METHOD_H +#define TAO_NOTIFY_DELIVERY_METHOD_H +#include "ace/pre.h" + +#include "notify_export.h" +#include "Method_Request.h" +#include "Event.h" +#include "Routing_Slip.h" +#include "Types.h" +#include "Refcountable.h" + +#include "ace/Message_Block.h" +#include <ace/Vector_T.h> + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace TAO_NOTIFY +{ + +/** + * @class Delivery_Method + * + * @brief Base class for requests to deliver events to destinations. + * + */ +class TAO_Notify_Export Delivery_Method : public TAO_Notify_Method_Request +{ +public: + /// Constructor + Delivery_Method (const Delivery_Request_Ptr & delivery_request); + + /// Destructor + virtual ~Delivery_Method (); + + /// Obtain the event. + const TAO_Notify_Event& event (void) const; + +protected: + // derived classes can copy themselves, but + // you cant copy-construct a Delivery_Method + Delivery_Method (const Delivery_Method & rhs); + + Delivery_Request_Ptr delivery_request_; +}; + +/// Exception/surprise return safe completion notification to the Delivery Request. +class TAO_Notify_Export Delivery_Method_Complete +{ +public: + /// Construct with the Delivery Request to be notified. + Delivery_Method_Complete (const Delivery_Request_Ptr & delivery_request); + /// The distructor sends the notification + ~Delivery_Method_Complete (); + /// Abandon if notification should not be sent (unlikely!) + void abandon (); +private: + Delivery_Request_Ptr delivery_request_; + bool abandoned_; +}; +} //namespace TAO_NOTIFY + +#if defined (__ACE_INLINE__) +#include "Delivery_Method.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/post.h" +#endif /* TAO_NOTIFY_DELIVERY_METHOD_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.cpp b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.cpp new file mode 100644 index 00000000000..e0eec8bb5a6 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.cpp @@ -0,0 +1,192 @@ +// $Id$ + +#include "Delivery_Method_Dispatch.h" + +#if ! defined (__ACE_INLINE__) +#include "Delivery_Method_Dispatch.inl" +#endif /* __ACE_INLINE__ */ + +ACE_RCSID(RT_Notify, Delivery_Method_Dispatch, "$Id$") + +#include "Delivery_Request.h" +#include "ProxySupplier.h" +#include "Consumer.h" +#include "tao/debug.h" +//#define DEBUG_LEVEL 9 +#define DEBUG_LEVEL TAO_debug_level + +////////////////////////////////////////////////////////// + +namespace TAO_NOTIFY +{ + +Delivery_Method_Dispatch::Delivery_Method_Dispatch ( + const TAO_NOTIFY::Delivery_Request_Ptr& delivery_request, + TAO_Notify_ProxySupplier* proxy_supplier, + bool filtering) + : Delivery_Method (delivery_request) + , proxy_supplier_ (proxy_supplier) + , refcountable_guard_ (*proxy_supplier) + , filtering_ (filtering) +{ + delivery_request->set_delivery_type (1); + IdVec ids(3); + proxy_supplier->get_id_path (ids); + delivery_request->set_destination_id (ids); +} + +Delivery_Method_Dispatch::Delivery_Method_Dispatch ( + const Delivery_Method_Dispatch & rhs) + : Delivery_Method (rhs.delivery_request_) + , proxy_supplier_ (rhs.proxy_supplier_) + , refcountable_guard_ (*rhs.proxy_supplier_) + , filtering_ (rhs.filtering_) +{ +} + +Delivery_Method_Dispatch::~Delivery_Method_Dispatch () +{ +} + +//static +Delivery_Method_Dispatch * +Delivery_Method_Dispatch::create ( + const Delivery_Request_Ptr& delivery_request, + TAO_Notify_EventChannelFactory &ecf, + TAO_InputCDR & cdr + ACE_ENV_ARG_DECL) +{ + bool ok = true; + Delivery_Method_Dispatch * result = 0; + ACE_CString textpath; + CORBA::ULong count; + if (cdr.read_ulong (count)) + { + IdVec id_path (count); + for (size_t nid = 0; ok && nid < count; ++nid) + { + TAO_Notify_Object_Id id = 0; + if ( cdr.read_long (id)) + { + id_path.push_back (id); + char idbuf[20]; + ACE_OS::snprintf (idbuf, sizeof(idbuf)-1, "/%d", ACE_static_cast (int, id)); + textpath += idbuf; + } + else + { + ok = false; + } + } + + if (ok) + { + TAO_Notify_ProxySupplier* proxy_supplier = ecf.find_proxy_supplier (id_path, + 0 ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + if (proxy_supplier != 0) + { + if (DEBUG_LEVEL > 6) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Delivery_Method reload event for %s\n") + , textpath.c_str() + )); + ACE_NEW_NORETURN (result, + Delivery_Method_Dispatch (delivery_request, proxy_supplier, true)); + } + else + { + TAO_Notify_ProxyConsumer * proxy_consumer = ecf.find_proxy_consumer (id_path, 0 ACE_ENV_ARG_PARAMETER); //@@todo + if (proxy_consumer == 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch::unmarshal: unknown proxy id %s\n") + , textpath.c_str() + )); + } + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch::unmarshal: wrong type of proxy id %s\n") + , textpath.c_str() + )); + } + } + } + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch::unmarshal: Cant read proxy id path\n") + )); + } + } + return result; +} + + +TAO_Notify_Method_Request* +Delivery_Method_Dispatch::copy (void) +{ + return new Delivery_Method_Dispatch (*this); +} + +int +Delivery_Method_Dispatch::execute (ExecuteOption eo ACE_ENV_ARG_DECL) +{ + ACE_ASSERT(this->proxy_supplier_ != 0); + ACE_ASSERT(this->delivery_request_ != 0); + ACE_ASSERT(! this->delivery_request_->event().null()); + + if (eo == TAO_Notify_Method_Request::DISCARD) + { + this->delivery_request_->complete(); + return 0; + } + // Note : Unlike suppliers, if the consumer has shutdown() then we can safely discard the + // event. + if (this->proxy_supplier_->has_shutdown()) + { + if (DEBUG_LEVEL > 0)ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch: proxy_supplier is shut down. Discard delivery.\n") + )); + this->delivery_request_->complete(); + return 0; + } + + // Same logic as above + TAO_Notify_Consumer* consumer = this->proxy_supplier_->consumer (); + if (consumer == 0) + { + if (DEBUG_LEVEL > 0)ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch: consumer is null. Discard delivery.\n") + )); + this->delivery_request_->complete(); + return 0; + } + + if (this->filtering_) + { + CORBA::Boolean val = this->proxy_supplier_->check_filters (* this->delivery_request_->event() ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + if (! val) + { + if (DEBUG_LEVEL > 0)ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch: Proxysupplier %d filter discards delivery.\n"), + ACE_static_cast (int, this->proxy_supplier_->id ()) + )); + + this->delivery_request_->complete(); + return 0; + } + } + + if (DEBUG_LEVEL > 0)ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Delivery_Method_Dispatch: Push event to Proxysupplier %d.\n"), + ACE_static_cast (int, this->proxy_supplier_->id ()) + )); + + consumer->push (this->delivery_request_); // calls delivery_request_->complete() + + return 0; +} + +} //namespace TAO_NOTIFY diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.h b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.h new file mode 100644 index 00000000000..4378e0149c6 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Dispatch.h @@ -0,0 +1,78 @@ +/* -*- C++ -*- */ +/** + * @file Delivery_Method_Dispatch.h + * + * $Id$ + * + * @author Pradeep Gore <pradeep@oomworks.com> + * + * + */ + +#ifndef TAO_NOTIFY_DELIVERY_METHOD_DISPATCH_H +#define TAO_NOTIFY_DELIVERY_METHOD_DISPATCH_H +#include "ace/pre.h" + +#include "notify_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "Delivery_Method.h" +#include "Types.h" + +namespace TAO_NOTIFY +{ +/** + * @class Delivery_Method_Dispatch + * + * @brief Dispatchs an event to a proxy supplier. + * + */ +class TAO_Notify_Export Delivery_Method_Dispatch : public Delivery_Method +{ +public: + /// an arbitrary code (Octet) to identify this delivery method type in persistent storage + enum {persistence_code = 1}; + /// Constructor + Delivery_Method_Dispatch ( + const Delivery_Request_Ptr& delivery_request, + TAO_Notify_ProxySupplier* proxy_supplier, + bool filtering = true); + + Delivery_Method_Dispatch (const Delivery_Method_Dispatch & rhs); + + static Delivery_Method_Dispatch * create ( + const Delivery_Request_Ptr& delivery_request, + TAO_Notify_EventChannelFactory &ecf, + TAO_InputCDR & cdr + ACE_ENV_ARG_DECL); + + /// Destructor + ~Delivery_Method_Dispatch (); + + /// Create a copy of this object. + TAO_Notify_Method_Request* copy (void); + + /// Execute the Request + virtual int execute (ExecuteOption eo ACE_ENV_ARG_DECL); + +private: + /// Proxy Supplier that we use. + TAO_Notify_ProxySupplier* proxy_supplier_; + + /// Guard to automatically inc/decr ref count on the proxy. + TAO_Notify_Refcountable_Guard refcountable_guard_; + + bool filtering_; +}; + +} //namespace TAO_NOTIFY + +#if defined (__ACE_INLINE__) +#include "Delivery_Method_Dispatch.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/post.h" +#endif /* TAO_NOTIFY_DELIVERY_METHOD_DISPATCH_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.cpp b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.cpp new file mode 100644 index 00000000000..8cfe9b0d53a --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.cpp @@ -0,0 +1,179 @@ +// $Id$ + +#include "Delivery_Method_Lookup.h" + +#if ! defined (__ACE_INLINE__) +#include "Delivery_Method_Lookup.inl" +#endif /* __ACE_INLINE__ */ + +ACE_RCSID(RT_Notify, TAO_Notify_Method_Request_Lookup, "$Id$") + +#include "Event_Map_T.h" +#include "ProxySupplier.h" +#include "ProxyConsumer.h" + +#include "orbsvcs/ESF/ESF_Proxy_Collection.h" + +#include "tao/debug.h" + +namespace TAO_NOTIFY +{ + +////////////////// +// Delivery Request +Delivery_Method_Lookup::Delivery_Method_Lookup (const TAO_NOTIFY::Delivery_Request_Ptr & delivery_request, + TAO_Notify_ProxyConsumer* proxy_consumer) + : Delivery_Method (delivery_request) + , TAO_ESF_Worker<TAO_Notify_ProxySupplier> () // gcc 3.2 makes me do this + , proxy_consumer_ (proxy_consumer) + , refcountable_guard_ (*proxy_consumer) +{ + delivery_request->set_delivery_type (persistence_code); + IdVec ids(3); + proxy_consumer->get_id_path (ids); + delivery_request->set_destination_id (ids); +} + +Delivery_Method_Lookup::Delivery_Method_Lookup( const Delivery_Method_Lookup & rhs) + : Delivery_Method (rhs.delivery_request_) + , TAO_ESF_Worker<TAO_Notify_ProxySupplier> () // gcc 3.2 makes me do this + , proxy_consumer_ (rhs.proxy_consumer_) + , refcountable_guard_ (*rhs.proxy_consumer_) +{ +} + +Delivery_Method_Lookup::~Delivery_Method_Lookup () +{ +} + +//static +Delivery_Method_Lookup * +Delivery_Method_Lookup::create ( + const Delivery_Request_Ptr& delivery_request, + TAO_Notify_EventChannelFactory &ecf, + TAO_InputCDR & cdr + ACE_ENV_ARG_DECL) +{ + bool ok = true; + Delivery_Method_Lookup * result = 0; + CORBA::ULong count; + if (cdr.read_ulong (count)) + { + IdVec id_path (count); + for (size_t nid = 0; ok && nid < count; ++nid) + { + TAO_Notify_Object_Id id = 0; + if ( cdr.read_long (id)) + { + id_path.push_back (id); + } + else + { + ok = false; + } + } + + if (ok) + { + TAO_Notify_ProxyConsumer * proxy_consumer = ecf.find_proxy_consumer (id_path, + 0 ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + if (proxy_consumer != 0) + { + ACE_NEW_NORETURN (result, + Delivery_Method_Lookup (delivery_request, proxy_consumer)); + } + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Delivery_Method_Lookup::unmarshal: unknown proxy id\n") + )); + } + } + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Delivery_Method_Lookup::unmarshal: Cant read proxy id path\n") + )); + } + } + return result; +} + + +TAO_Notify_Method_Request* +Delivery_Method_Lookup::copy (void) +{ + return new Delivery_Method_Lookup (*this); +} + +int +Delivery_Method_Lookup::execute (ExecuteOption eo ACE_ENV_ARG_DECL) +{ + ACE_UNUSED_ARG (eo); + ACE_ASSERT(this->delivery_request_ != 0); + ACE_ASSERT(this->proxy_consumer_ != 0); + ACE_ASSERT(! this->delivery_request_->event().null()); + ACE_ASSERT(eo == TAO_Notify_Method_Request::EXECUTE); + + // Report request complete when this method exits. If the request isn't filtered + // then a new request will be created for each destination consumer. + Delivery_Method_Complete complete (this->delivery_request_); + + // Note : The ProxyConsumer may very well shutdown() before we get here. It should still be + // usable for checking filters, and we still want to deliver the events that were pushed. + + TAO_Notify_Event_Ptr pevent = this->delivery_request_->event (); + CORBA::Boolean val = this->proxy_consumer_->check_filters (*pevent ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + + if (TAO_debug_level > 1) + ACE_DEBUG ((LM_DEBUG, "Proxyconsumer %x filter eval result = %d\n",this->proxy_consumer_ , val)); + + // Filter failed - do nothing. + if (val == 0) + { + return 0; + } + + TAO_Notify_Consumer_Map* map = this->proxy_consumer_->map(); + ACE_ASSERT(map != 0); + + TAO_Notify_Consumer_Map::ENTRY* entry = map->find (pevent->type () ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + TAO_Notify_ProxySupplier_Collection* consumers = 0; + + if (entry != 0) + { + consumers = entry->collection (); + + if (consumers != 0) + { + consumers->for_each (this ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + } + + map->release (entry); + } + + // Get the consumers subscribed to all events. + consumers = map->broadcast_collection (); + + if (consumers != 0) + { + consumers->for_each (this ACE_ENV_ARG_PARAMETER); + } + return 0; +} + +void +Delivery_Method_Lookup::work (TAO_Notify_ProxySupplier* proxy ACE_ENV_ARG_DECL_NOT_USED) +{ + ACE_ASSERT(proxy != 0); + ACE_ASSERT(this->delivery_request_ != 0); + ACE_ASSERT(this->delivery_request_->routing_slip() != 0); + this->delivery_request_->routing_slip()->dispatch (proxy, true); +} + +} //namespace TAO_NOTIFY diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.h b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.h new file mode 100644 index 00000000000..cfbf5699dc8 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Method_Lookup.h @@ -0,0 +1,71 @@ +/* -*- C++ -*- */ +/** + * @file Delivery_Method_Lookup.h + * + * $Id$ + * + * @author Pradeep Gore <pradeep@oomworks.com> + * + * + */ + +#ifndef TAO_Notify_LOOKUP_METHOD_REQUEST_H +#define TAO_Notify_LOOKUP_METHOD_REQUEST_H +#include "ace/pre.h" + +#include "notify_export.h" +#include "Delivery_Method.h" +#include "Types.h" +#include "orbsvcs/ESF/ESF_Worker.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace TAO_NOTIFY +{ +class TAO_Notify_Export Delivery_Method_Lookup + : public Delivery_Method + , public TAO_ESF_Worker<TAO_Notify_ProxySupplier> +{ +public: + /// an arbitrary code (Octet) to identify this type of event in persistent storage + enum {persistence_code = 2}; + /// Constructor + Delivery_Method_Lookup(const TAO_NOTIFY::Delivery_Request_Ptr & delivery_request, TAO_Notify_ProxyConsumer* proxy_consumer); + Delivery_Method_Lookup(const Delivery_Method_Lookup & rhs); + + /// Destructor + ~Delivery_Method_Lookup (); + + /// Create a copy of this object. + TAO_Notify_Method_Request* copy (void); + + static Delivery_Method_Lookup * create ( + const Delivery_Request_Ptr& delivery_request, + TAO_Notify_EventChannelFactory &ecf, + TAO_InputCDR & cdr + ACE_ENV_ARG_DECL); + + /// Execute the Request + virtual int execute (ExecuteOption eo ACE_ENV_ARG_DECL); + + ///= TAO_ESF_Worker method + void work (TAO_Notify_ProxySupplier* proxy_supplier ACE_ENV_ARG_DECL); + +private: + /// ProxyConsumer supplying event. + TAO_Notify_ProxyConsumer* proxy_consumer_; + + /// Guard to automatically inc/decr ref count on the proxy. + TAO_Notify_Refcountable_Guard refcountable_guard_; +}; + +} // namespace TAO_NOTIFY + +#if defined (__ACE_INLINE__) +#include "Delivery_Method_Lookup.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/post.h" +#endif /* TAO_Notify_LOOKUP_METHOD_REQUEST_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.cpp b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.cpp new file mode 100644 index 00000000000..62e6aa24a63 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.cpp @@ -0,0 +1,87 @@ +// $Id$ + +#include "Delivery_Request.h" + +#if ! defined (__ACE_INLINE__) +#include "Delivery_Request.inl" +#endif /* __ACE_INLINE__ */ + +#include "Routing_Slip.h" +#include "tao/debug.h" + +//#define DEBUG_LEVEL 9 +#define DEBUG_LEVEL TAO_debug_level + +namespace TAO_NOTIFY +{ + +/////////////////// +// Delivery_Request +Delivery_Request::Delivery_Request (const Routing_Slip_Ptr & routing_slip, size_t request_id) + : routing_slip_ (routing_slip) + , request_id_ (request_id) + , delivery_type_ (0) +{ + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Delivery_Request:: constructor\n") + )); +} + +Delivery_Request::~Delivery_Request () +{ + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Delivery_Request:: destructor\n") + )); +} + +// DO NOT INLINE THIS. It uses the Routing_Slip_Ptr which cannot be declared at +// the time Delivery_Request.inl is compiled. +void +Delivery_Request::complete () +{ + routing_slip_->delivery_request_complete (this->request_id_); +} + +// DO NOT INLINE THIS. It uses the Routing_Slip_Ptr which cannot be declared at +// the time Delivery_Request.inl is compiled. +const TAO_Notify_Event_Ptr & +Delivery_Request::event () const +{ + return this->routing_slip_->event (); +} + +void +Delivery_Request::marshal (TAO_OutputCDR & cdr) +{ + if (this->delivery_type_ != 0) + { + cdr.write_octet (this->delivery_type_); + size_t dest_count = this->destination_id_.size (); + cdr.write_ulong (dest_count); + for (size_t ndest = 0; ndest < dest_count; ++ ndest) + { + cdr.write_ulong (this->destination_id_ [ndest]); + } + } +} + +} // namespace + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +//template class ACE_Auto_Basic_Ptr<TAO_NOTIFY::Routing_Slip>; +//template class ACE_Strong_Bound_Ptr<TAO_NOTIFY::Routing_Slip, TAO_SYNCH_MUTEX>; +//template class ACE_Auto_Basic_Ptr<TAO_NOTIFY::Delivery_Request>; +//template class ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX>; +// Duplicated in Routing_Slip.cpp +//template class ACE_Vector <TAO_NOTIFY::Delivery_Request_Ptr>; +//template class ACE_Array_Base<ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX> >; +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +//#pragma instantiate ACE_Auto_Basic_Ptr<TAO_NOTIFY::Routing_Slip> +//#pragma instantiate ACE_Strong_Bound_Ptr<TAO_NOTIFY::Routing_Slip,TAO_SYNCH_MUTEX> +//#pragma instantiate ACE_Auto_Basic_Ptr<TAO_NOTIFY::Delivery_Request> +//#pragma instantiate ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX> +// Duplicated in Routing_Slip.cpp +//#pragma instantiate ACE_Vector <TAO_NOTIFY::Delivery_Request_Ptr> +//#pragma instantiate ACE_Array_Base<ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX> > +#endif /*ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ + diff --git a/TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.h b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.h new file mode 100644 index 00000000000..6f6a4a7a945 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Delivery_Request.h @@ -0,0 +1,121 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef TAO_NOTIFY_DELIVERY_REQUEST_H +#define TAO_NOTIFY_DELIVERY_REQUEST_H +#include /**/ "ace/pre.h" + +#include "notify_export.h" +#include "Object.h" +#include "Event.h" +#include <ace/Vector_T.h> + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + + +// Forward declarations of classes/pointers/collections referenced +// in this header +class TAO_Notify_EventChannelFactory; + +namespace TAO_NOTIFY +{ + +// Forward declarations of TAO_NOTIFY classes/pointers/collections declared +// in this header +class Delivery_Request; +/// A reference-counted smart pointer to a Delivery_Request. +typedef ACE_Strong_Bound_Ptr<Delivery_Request, TAO_SYNCH_MUTEX> Delivery_Request_Ptr; + +// Forward declarations of TAO_NOTIFY classes/pointers/collections referenced +// in this header + +class Routing_Slip; +typedef ACE_Strong_Bound_Ptr<Routing_Slip, TAO_SYNCH_MUTEX> Routing_Slip_Ptr; + +/// \brief Represents a request to deliver an event to a particular destination. +/// +/// A Routing Slip contains a collection of Delivery Requests. +/// A Delivery Request is associated with a Delivery Method. Delivery Methods +/// should be lightweight objects because they are copied, queued, and otherwise +/// passed around while they are waiting to be executed. The Delivery Request is +/// more stable. +class TAO_Notify_Export Delivery_Request +{ +public: + /// Normal constructor + /// \param routing_slip the routing slip that owns this Delivery Request. + /// \param request_id an id that identifies this Delivery Request to the Routing Slip. + Delivery_Request (const Routing_Slip_Ptr & routing_slip, size_t request_id); + + /// \brief A static "factory" method for use during restart. + /// + /// \param routing_slip. The routing slip to which the new Delivery Request should be attached. + /// \param request_id The id used to identify this Delivery Request to the Routing Slip. + /// \param ecf The EventChannelFactory responsible for reloading this Delivery Method. + /// \param cdr A CDR stream from which the peristent information for this Delivery Requect can be retrieved. + /// \return a pointer to the newly-allocated Delivery Request + static Delivery_Request_Ptr create ( + const Routing_Slip_Ptr & routing_slip, + size_t request_id, + TAO_Notify_EventChannelFactory & ecf, + TAO_InputCDR & cdr); + + /// a normal destructor. + ~Delivery_Request (); + + /// \brief A method to indicate the delivery is complete. + /// + /// To be called by the delivery method associated with this delivery request. + void complete (); + + /// \brief An accessor method for the event associated with the Routing Slip that owns this Delivery request. + const TAO_Notify_Event_Ptr & event () const; + + /// \brief An accessor method for the routing slip that owns this request. + const Routing_Slip_Ptr & routing_slip ()const; + + /// \brief Capture Delivery Type for the Delivery Method + /// + /// Called by the delivery method to capture information that should be persisted. + void set_delivery_type (ACE_CDR::Octet type); + + /// \brief Capture destination ID for the Delivery Request. + /// + /// Called by the delivery method to capture information that should be persisted. + void set_destination_id (IdVec & destination_id); + + /// \brief Marshal peristent information for this delivery request and its delivery methods into a CDR stream. + /// + /// Called during persistent event storage. + void marshal (TAO_OutputCDR & cdr); + + // Meaningless, but needed by ACE_Vector on some platforms (gcc2.x LynxOS) + bool operator == (const Delivery_Request & rhs) const; + // Meaningless, but needed by ACE_Vector on some platforms + bool operator != (const Delivery_Request & rhs) const; + +private: + /// No null constructor. + Delivery_Request (); + /// No copy constructor. + Delivery_Request (const Delivery_Request & rhs); + /// no assignment operator + Delivery_Request & operator = (const Delivery_Request & rhs); + +private: + Routing_Slip_Ptr routing_slip_; + size_t request_id_; + ACE_CDR::Octet delivery_type_; + IdVec destination_id_; +}; + +} // namespace + +#if defined (__ACE_INLINE__) +#include "Delivery_Request.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* TAO_NOTIFY_DELIVERY_REQUEST_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventChannel.cpp b/TAO/orbsvcs/orbsvcs/Notify/EventChannel.cpp index 3985ef9d899..411f9fad2e6 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/EventChannel.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/EventChannel.cpp @@ -16,6 +16,13 @@ #include "Builder.h" #include "Find_Worker_T.h" #include "Seq_Worker_T.h" +#include "Topology_Saver.h" +#include "Save_Persist_Worker_T.h" +#include "Reconnect_Worker_T.h" + +#include "tao/debug.h" +//#define DEBUG_LEVEL 9 +#define DEBUG_LEVEL TAO_debug_level ACE_RCSID(Notify, TAO_Notify_EventChannel, "$Id$") @@ -54,7 +61,7 @@ TAO_Notify_EventChannel::init (TAO_Notify_EventChannelFactory* ecf , const CosNotification::AdminProperties & initial_admin ACE_ENV_ARG_DECL) { - this->TAO_Notify_Object::init (ecf); + this->TAO_NOTIFY::Topology_Object::init (ecf); this->ecf_ = ecf; @@ -109,16 +116,69 @@ TAO_Notify_EventChannel::init (TAO_Notify_EventChannelFactory* ecf this->set_admin (initial_admin ACE_ENV_ARG_PARAMETER); ACE_CHECK; - CosNotifyChannelAdmin::AdminID id; + // Note originally default admins were allocated here, bt this caused problems + // attempting to save the topology changes before the Event Channel was completely + // constructed and linked to the ECF. + // Lazy evaluation also avoids creating unneded admins. +} + + +void +TAO_Notify_EventChannel::init (TAO_Notify_EventChannelFactory* ecf + ACE_ENV_ARG_DECL) +{ + this->TAO_NOTIFY::Topology_Object::init (ecf); + + this->ecf_ = ecf; + + this->ecf_->_incr_refcnt (); + + // Init ca_container_ + ACE_NEW_THROW_EX (this->ca_container_, + TAO_Notify_ConsumerAdmin_Container (), + CORBA::INTERNAL ()); + ACE_CHECK; + + this->ca_container_->init (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + + // Init ca_container_ + ACE_NEW_THROW_EX (this->sa_container_, + TAO_Notify_SupplierAdmin_Container (), + CORBA::INTERNAL ()); + ACE_CHECK; + + this->sa_container_->init (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + + TAO_Notify_AdminProperties* admin_properties = 0; + + // Set the admin properties. + ACE_NEW_THROW_EX (admin_properties, + TAO_Notify_AdminProperties (), + CORBA::NO_MEMORY ()); + ACE_CHECK; + + this->admin_properties_ = admin_properties; + + // create the event manager. @@ use factory + ACE_NEW_THROW_EX (this->event_manager_, + TAO_Notify_Event_Manager (), + CORBA::INTERNAL ()); + ACE_CHECK; + + this->event_manager_->init (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; - // Set the default ConsumerAdmin. - this->default_consumer_admin_ = this->new_for_consumers (CosNotifyChannelAdmin::OR_OP, id ACE_ENV_ARG_PARAMETER); + const CosNotification::QoSProperties &default_ec_qos = + TAO_Notify_PROPERTIES::instance ()->default_event_channel_qos_properties (); + + this->set_qos (default_ec_qos ACE_ENV_ARG_PARAMETER); ACE_CHECK; - // Set the default SupplierAdmin. - this->default_supplier_admin_ = this->new_for_suppliers (CosNotifyChannelAdmin::OR_OP, id ACE_ENV_ARG_PARAMETER); } + void TAO_Notify_EventChannel::_add_ref (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) { @@ -214,20 +274,63 @@ TAO_Notify_EventChannel::MyFactory (ACE_ENV_SINGLE_ARG_DECL) } CosNotifyChannelAdmin::ConsumerAdmin_ptr -TAO_Notify_EventChannel::default_consumer_admin (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) +TAO_Notify_EventChannel::default_consumer_admin (ACE_ENV_SINGLE_ARG_DECL) ACE_THROW_SPEC (( CORBA::SystemException )) { + if (CORBA::is_nil (default_consumer_admin_.in ())) + { + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->default_admin_mutex_, CosNotifyChannelAdmin::ConsumerAdmin::_nil()); + if (CORBA::is_nil (default_consumer_admin_.in ())) + { + CosNotifyChannelAdmin::AdminID id; + this->default_consumer_admin_ = this->new_for_consumers (CosNotifyChannelAdmin::OR_OP, id ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (CosNotifyChannelAdmin::ConsumerAdmin::_nil()); + // Wish there was a better way to do this! + PortableServer::ServantBase * admin_servant = + this->poa_->reference_to_servant ( + this->default_consumer_admin_.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (CosNotifyChannelAdmin::ConsumerAdmin::_nil()); + TAO_Notify_Admin * pAdmin = dynamic_cast <TAO_Notify_Admin *> (admin_servant); + ACE_ASSERT (pAdmin != 0); // if this assert triggers, we have mixed implementations? + if (pAdmin != 0) + { + pAdmin->set_default (true); + } + } + } return CosNotifyChannelAdmin::ConsumerAdmin::_duplicate (this->default_consumer_admin_.in ()); } CosNotifyChannelAdmin::SupplierAdmin_ptr -TAO_Notify_EventChannel::default_supplier_admin (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) +TAO_Notify_EventChannel::default_supplier_admin (ACE_ENV_SINGLE_ARG_DECL) ACE_THROW_SPEC (( CORBA::SystemException )) { + if (CORBA::is_nil (default_supplier_admin_.in ())) + { + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->default_admin_mutex_, CosNotifyChannelAdmin::SupplierAdmin::_nil()); + if (CORBA::is_nil (default_supplier_admin_.in ())) + { + CosNotifyChannelAdmin::AdminID id; + this->default_supplier_admin_ = this->new_for_suppliers (CosNotifyChannelAdmin::OR_OP, id ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (CosNotifyChannelAdmin::SupplierAdmin::_nil()); + PortableServer::ServantBase * admin_servant = + this->poa_->poa()->reference_to_servant ( + this->default_supplier_admin_.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + TAO_Notify_Admin * pAdmin = dynamic_cast <TAO_Notify_Admin *> (admin_servant); + ACE_ASSERT (pAdmin != 0); // if this assert triggers, we have mixed implementations? + if (pAdmin != 0) + { + pAdmin->set_default (true); + } + } + } return CosNotifyChannelAdmin::SupplierAdmin::_duplicate (this->default_supplier_admin_.in ()); } @@ -248,7 +351,12 @@ TAO_Notify_EventChannel::new_for_consumers (CosNotifyChannelAdmin::InterFilterGr )) { - return TAO_Notify_PROPERTIES::instance()->builder()->build_consumer_admin (this, op, id ACE_ENV_ARG_PARAMETER); + ::CosNotifyChannelAdmin::ConsumerAdmin_var ca = + TAO_Notify_PROPERTIES::instance()->builder()->build_consumer_admin (this, op, id ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (ca._retn ()); + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (ca._retn ()); + return ca._retn (); } ::CosNotifyChannelAdmin::SupplierAdmin_ptr @@ -260,7 +368,12 @@ TAO_Notify_EventChannel::new_for_suppliers (CosNotifyChannelAdmin::InterFilterGr CORBA::SystemException )) { - return TAO_Notify_PROPERTIES::instance()->builder()->build_supplier_admin (this, op, id ACE_ENV_ARG_PARAMETER); + ::CosNotifyChannelAdmin::SupplierAdmin_var sa = + TAO_Notify_PROPERTIES::instance()->builder()->build_supplier_admin (this, op, id ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (sa._retn ()); + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (sa._retn ()); + return sa._retn (); } CosNotifyChannelAdmin::ConsumerAdmin_ptr @@ -337,21 +450,21 @@ TAO_Notify_EventChannel::get_admin (ACE_ENV_SINGLE_ARG_DECL) } CosEventChannelAdmin::ConsumerAdmin_ptr -TAO_Notify_EventChannel::for_consumers (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) +TAO_Notify_EventChannel::for_consumers (ACE_ENV_SINGLE_ARG_DECL) ACE_THROW_SPEC (( CORBA::SystemException )) { - return CosEventChannelAdmin::ConsumerAdmin::_duplicate (this->default_consumer_admin_.in ()); + return this->default_consumer_admin(ACE_ENV_SINGLE_ARG_PARAMETER); } CosEventChannelAdmin::SupplierAdmin_ptr -TAO_Notify_EventChannel::for_suppliers (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) +TAO_Notify_EventChannel::for_suppliers (ACE_ENV_SINGLE_ARG_DECL) ACE_THROW_SPEC (( CORBA::SystemException )) { - return CosEventChannelAdmin::SupplierAdmin::_duplicate (this->default_supplier_admin_.in ()); + return this->default_supplier_admin (ACE_ENV_SINGLE_ARG_PARAMETER); } void @@ -367,6 +480,154 @@ TAO_Notify_EventChannel::validate_qos (const CosNotification::QoSProperties & /* ACE_THROW (CORBA::NO_IMPLEMENT ()); } +void +TAO_Notify_EventChannel::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL) +{ + bool changed = this->self_changed_; + this->self_changed_ = false; + this->children_changed_ = false; + + if (is_persistent ()) + { + TAO_NOTIFY::NVPList attrs; + this->save_attrs(attrs); + + bool want_all_children = saver.begin_object( + this->id(), "channel", attrs, changed ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + TAO_NOTIFY::Save_Persist_Worker<TAO_Notify_ConsumerAdmin> ca_wrk(saver, want_all_children); + + ACE_ASSERT(this->ca_container_ != 0); + this->ca_container_->collection()->for_each(&ca_wrk ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + TAO_NOTIFY::Save_Persist_Worker<TAO_Notify_SupplierAdmin> sa_wrk(saver, want_all_children); + ACE_ASSERT(this->sa_container_ != 0); + this->sa_container_->collection()->for_each(&sa_wrk ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + saver.end_object(this->id(), "channel" ACE_ENV_ARG_PARAMETER); + } +} + +namespace { + template<class T> + void add_attr(TAO_NOTIFY::NVPList& attrs, const T& prop) { + if (prop.is_valid()) + { + attrs.push_back(TAO_NOTIFY::NVP (prop)); + } + } +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +template void add_attr<TAO_NS_Property_Boolean>(TAO_NOTIFY::NVPList&, + const TAO_NS_Property_Boolean&); +template void add_attr<TAO_NS_Property_T<int> >(TAO_NOTIFY::NVPList&, + const TAO_NS_Property_T<int>&); +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#pragma instantiate void add_attr<TAO_NS_Property_Boolean>(\ + TAO_NOTIFY::NVPList&, const TAO_NS_Property_Boolean&) +#pragma instantiate void add_attr<TAO_NS_Property_T<int> >(\ + TAO_NOTIFY::NVPList&, const TAO_NS_Property_T<int>&) +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ +} + +void +TAO_Notify_EventChannel::save_attrs(TAO_NOTIFY::NVPList& attrs) +{ + TAO_Notify_Object::save_attrs(attrs); + add_attr(attrs, this->admin_properties_->max_global_queue_length()); + add_attr(attrs, this->admin_properties_->max_consumers()); + add_attr(attrs, this->admin_properties_->max_suppliers()); + add_attr(attrs, this->admin_properties_->reject_new_events()); +} + +void +TAO_Notify_EventChannel::load_attrs(const TAO_NOTIFY::NVPList& attrs) +{ + TAO_Notify_Object::load_attrs(attrs); + attrs.load(this->admin_properties_->max_global_queue_length()); + attrs.load(this->admin_properties_->max_consumers()); + attrs.load(this->admin_properties_->max_suppliers()); + attrs.load(this->admin_properties_->reject_new_events()); + this->admin_properties_->init(); +} + +TAO_NOTIFY::Topology_Object * +TAO_Notify_EventChannel::load_child (const ACE_CString &type, + CORBA::Long id, + const TAO_NOTIFY::NVPList& attrs + ACE_ENV_ARG_DECL) +{ + TAO_NOTIFY::Topology_Object* result = this; + if (type == "consumer_admin") + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) EventChannel reload consumer_admin %d\n") + , ACE_static_cast (int, id) + )); + + // call special builder method to reload + TAO_Notify_Builder* bld = TAO_Notify_PROPERTIES::instance()->builder(); + TAO_Notify_ConsumerAdmin * ca = bld->build_consumer_admin ( + this, + id + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + ca->load_attrs (attrs); + if (ca->is_default ()) + { + CORBA::Object_var caob = this->poa_->servant_to_reference (ca ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + this->default_consumer_admin_ = + CosNotifyChannelAdmin::ConsumerAdmin::_narrow ( + caob.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + } + result = ca; + } + else if (type == "supplier_admin") + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) EventChannel reload supplier_admin %d\n") + , ACE_static_cast (int, id) + )); + TAO_Notify_Builder* bld = TAO_Notify_PROPERTIES::instance()->builder(); + + TAO_Notify_SupplierAdmin * sa = bld->build_supplier_admin ( + this, + id + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + sa->load_attrs (attrs); + if (sa->is_default ()) + { + CORBA::Object_var saob = this->poa_->servant_to_reference (sa ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + this->default_supplier_admin_ = + CosNotifyChannelAdmin::SupplierAdmin::_narrow ( + saob.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + } + result = sa; + } + return result; +} + +void +TAO_Notify_EventChannel::reconnect (ACE_ENV_SINGLE_ARG_DECL) +{ + TAO_NOTIFY::Reconnect_Worker<TAO_Notify_ConsumerAdmin> ca_wrk; + ACE_ASSERT(this->ca_container_ != 0); + this->ca_container_->collection()->for_each(&ca_wrk ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + TAO_NOTIFY::Reconnect_Worker<TAO_Notify_SupplierAdmin> sa_wrk; + ACE_ASSERT(this->sa_container_ != 0); + this->sa_container_->collection()->for_each(&sa_wrk ACE_ENV_ARG_PARAMETER); + ACE_CHECK; +} + #if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) template class TAO_Notify_Find_Worker_T<TAO_Notify_ConsumerAdmin @@ -387,6 +648,11 @@ template class TAO_Notify_Container_T <TAO_Notify_SupplierAdmin>; template class TAO_ESF_Shutdown_Proxy<TAO_Notify_ConsumerAdmin>; template class TAO_ESF_Shutdown_Proxy<TAO_Notify_SupplierAdmin>; +template class Save_Persist_Worker<TAO_Notify_ConsumerAdmin>; +template class Save_Persist_Worker<TAO_Notify_SupplierAdmin>; +template class TAO_NOTIFY::Reconnect_Worker<TAO_Notify_ConsumerAdmin>; +template class TAO_NOTIFY::Reconnect_Worker<TAO_Notify_SupplierAdmin>; + #elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) #pragma instantiate TAO_Notify_Find_Worker_T<TAO_Notify_ConsumerAdmin @@ -407,4 +673,9 @@ template class TAO_ESF_Shutdown_Proxy<TAO_Notify_SupplierAdmin>; #pragma instantiate TAO_ESF_Shutdown_Proxy<TAO_Notify_ConsumerAdmin> #pragma instantiate TAO_ESF_Shutdown_Proxy<TAO_Notify_SupplierAdmin> +#pragma instantiate Save_Persist_Worker<TAO_Notify_ConsumerAdmin> +#pragma instantiate Save_Persist_Worker<TAO_Notify_SupplierAdmin> +#pragma instantiate TAO_NOTIFY::Reconnect_Worker<TAO_Notify_ConsumerAdmin> +#pragma instantiate TAO_NOTIFY::Reconnect_Worker<TAO_Notify_SupplierAdmin> + #endif /*ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventChannel.h b/TAO/orbsvcs/orbsvcs/Notify/EventChannel.h index e334a2f03e5..68297ad2b0d 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/EventChannel.h +++ b/TAO/orbsvcs/orbsvcs/Notify/EventChannel.h @@ -21,7 +21,7 @@ #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "orbsvcs/CosNotifyChannelAdminS.h" - +#include "Topology_Object.h" #include "Object.h" class TAO_Notify_ConsumerAdmin; @@ -30,7 +30,7 @@ class TAO_Notify_EventChannelFactory; template <class TYPE> class TAO_Notify_Container_T; #if defined(_MSC_VER) -#if (_MSC_VER >= 1200) + #if (_MSC_VER >= 1200) #pragma warning(push) #endif /* _MSC_VER >= 1200 */ #pragma warning(disable:4250) @@ -42,9 +42,9 @@ template <class TYPE> class TAO_Notify_Container_T; * @brief Implementation of CosNotifyChannelAdmin::EventChannel * */ -class TAO_Notify_Serv_Export TAO_Notify_EventChannel - : public POA_CosNotifyChannelAdmin::EventChannel, - public virtual TAO_Notify_Object +class TAO_Notify_Serv_Export TAO_Notify_EventChannel + : public POA_CosNotifyChannelAdmin::EventChannel, + public TAO_NOTIFY::Topology_Parent { friend class TAO_Notify_Builder; @@ -64,6 +64,10 @@ public: , const CosNotification::AdminProperties & initial_admin ACE_ENV_ARG_DECL); + /// Init (for reload) + void init (TAO_Notify_EventChannelFactory* ecf + ACE_ENV_ARG_DECL); + /// Remove ConsumerAdmin from its container. void remove (TAO_Notify_ConsumerAdmin* consumer_admin ACE_ENV_ARG_DECL); @@ -74,11 +78,29 @@ public: virtual void _add_ref (ACE_ENV_SINGLE_ARG_DECL); virtual void _remove_ref (ACE_ENV_SINGLE_ARG_DECL); + // TAO_NOTIFY::Topology_Parent + + virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL); + virtual TAO_NOTIFY::Topology_Object* load_child (const ACE_CString &type, + CORBA::Long id, + const TAO_NOTIFY::NVPList& attrs + ACE_ENV_ARG_DECL); + virtual void reconnect (ACE_ENV_SINGLE_ARG_DECL); + + virtual TAO_Notify_Object_Id get_id () const {return id();} + + TAO_Notify_ProxyConsumer * find_proxy_consumer (TAO_NOTIFY::IdVec & id_path, size_t position ACE_ENV_ARG_DECL); + TAO_Notify_ProxySupplier * find_proxy_supplier (TAO_NOTIFY::IdVec & id_path, size_t position ACE_ENV_ARG_DECL); + /// Release virtual void release (void); /// Shutdown virtual int shutdown (ACE_ENV_SINGLE_ARG_DECL); + virtual void load_attrs(const TAO_NOTIFY::NVPList& attrs); + +protected: + virtual void save_attrs(TAO_NOTIFY::NVPList& attrs); protected: typedef TAO_Notify_Container_T <TAO_Notify_ConsumerAdmin> TAO_Notify_ConsumerAdmin_Container; @@ -94,6 +116,8 @@ protected: /// SupplierAdmin Container. TAO_Notify_SupplierAdmin_Container *sa_container_; + TAO_SYNCH_MUTEX default_admin_mutex_; + // Default Consumer Admin CosNotifyChannelAdmin::ConsumerAdmin_var default_consumer_admin_; diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.cpp b/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.cpp index debe138d960..a241b822ce8 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.cpp @@ -12,11 +12,22 @@ ACE_RCSID(Notify, TAO_Notify_EventChannelFactory, "$Id$") #include "Properties.h" #include "Factory.h" #include "Builder.h" +#include "Topology_Saver.h" +#include "Topology_Loader.h" +#include "Save_Persist_Worker_T.h" +#include "Reconnect_Worker_T.h" +#include "Event_Persistence_Strategy.h" +#include "Routing_Slip_Persistence_Manager.h" + #include "EventChannel.h" #include "Container_T.h" #include "Find_Worker_T.h" #include "Seq_Worker_T.h" +#include "tao/debug.h" +#define DEBUG_OFFSET 0 +#define DEBUG_LEVEL (TAO_debug_level + DEBUG_OFFSET) + typedef TAO_Notify_Find_Worker_T<TAO_Notify_EventChannel , CosNotifyChannelAdmin::EventChannel , CosNotifyChannelAdmin::EventChannel_ptr @@ -26,7 +37,12 @@ TAO_Notify_EventChannel_Find_Worker; typedef TAO_Notify_Seq_Worker_T<TAO_Notify_EventChannel> TAO_Notify_EventChannel_Seq_Worker; TAO_Notify_EventChannelFactory::TAO_Notify_EventChannelFactory (void) - :ec_container_ (0) + : ec_container_ (0) + , topology_save_seq_ (0) + , topology_factory_(0) + , reconnect_registry_(*this) + , loading_topology_ (false) + { } @@ -95,6 +111,17 @@ TAO_Notify_EventChannelFactory::init (PortableServer::POA_ptr poa ACE_ENV_ARG_DE // Make the Proxys acivate in this same POA. this->proxy_poa_ = this->object_poa_; + + // Note topology factory is configured separately from the "builder" mediated + // objects since it is independant of the "style" of Notification Service. + this->topology_factory_ = + ACE_Dynamic_Service <TAO_NOTIFY::Topology_Factory>::instance ("Topology_Factory"); + + this->load_topology (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + + this->load_event_persistence (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; } void @@ -121,6 +148,7 @@ TAO_Notify_EventChannelFactory::remove (TAO_Notify_EventChannel* event_channel A { this->ec_container_->remove (event_channel ACE_ENV_ARG_PARAMETER); ACE_CHECK; + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); } int @@ -152,11 +180,16 @@ TAO_Notify_EventChannelFactory::get_default_filter_factory (ACE_ENV_SINGLE_ARG_D , CosNotification::UnsupportedAdmin )) { - return TAO_Notify_PROPERTIES::instance()->builder()->build_event_channel (this + CosNotifyChannelAdmin::EventChannel_var ec = + TAO_Notify_PROPERTIES::instance()->builder()->build_event_channel (this , initial_qos , initial_admin , id ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (ec._retn ()); + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (ec._retn ()); + return ec._retn (); } CosNotifyChannelAdmin::ChannelIDSeq* @@ -182,6 +215,260 @@ TAO_Notify_EventChannelFactory::get_event_channel (CosNotifyChannelAdmin::Channe return find_worker.resolve (id, *this->ec_container_ ACE_ENV_ARG_PARAMETER); } +void +TAO_Notify_EventChannelFactory::set_topology_factory(TAO_NOTIFY::Topology_Factory* f) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Debug Topology_Factory installed in EventChannelFactory.\n") + )); + // If the above meessage appears when you don't expect it + // use svc.conf to install the topology factory rather + // than calling this method. + this->topology_factory_ = f; +} + +void +TAO_Notify_EventChannelFactory::load_topology (ACE_ENV_SINGLE_ARG_DECL) +{ + this->loading_topology_ = true; + if (this->topology_factory_ != 0) + { + auto_ptr<TAO_NOTIFY::Topology_Loader> tl(this->topology_factory_->create_loader()); + if (tl.get () != 0) + { + tl->load (this ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + } + else + { + if (TAO_debug_level > 0) + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Topology persistence disabled.\n"))); + } + this->loading_topology_ = false; +} +bool +TAO_Notify_EventChannelFactory::is_persistent () const +{ + return true; +} + +void +TAO_Notify_EventChannelFactory::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL) +{ + bool changed = this->self_changed_; + this->self_changed_ = false; + this->children_changed_ = false; + + TAO_NOTIFY::NVPList attrs; // ECF has no attributes + + bool want_all_children = + saver.begin_object(0, "channel_factory", attrs, changed ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + // for each deleted child + // delete_child // if the child has persistence. + + TAO_NOTIFY::Save_Persist_Worker<TAO_Notify_EventChannel> wrk(saver, want_all_children); + + ACE_ASSERT(this->ec_container_ != 0); + this->ec_container_->collection()->for_each(&wrk ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + if (want_all_children || this->reconnect_registry_.is_changed ()) + { + this->reconnect_registry_.save_persistent(saver ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + saver.end_object(0, "channel_factory" ACE_ENV_ARG_PARAMETER); +} + +void +TAO_Notify_EventChannelFactory::load_event_persistence (ACE_ENV_SINGLE_ARG_DECL) +{ +#ifdef EVENT_PERISISTENCE_SUPPORT //@@todo + TAO_NOTIFY::Event_Persistence_Strategy * strategy = + ACE_Dynamic_Service <TAO_NOTIFY::Event_Persistence_Strategy>::instance ("Event_Persistence"); + if (strategy != 0) + { + if (this->topology_factory_ != 0) + { + Event_Persistence_Factory * factory = strategy->get_factory (); + if (factory != 0) + { + for ( + Routing_Slip_Persistence_Manager * rspm = factory->first_reload_manager(); + rspm != 0; + rspm = rspm->load_next ()) + { + TAO_NOTIFY::Routing_Slip_Ptr routing_slip = Routing_Slip::create (*this, rspm); + if (!routing_slip.null ()) + { + this->routing_slip_restart_set_.insert (routing_slip); + } + else + { + //@@todo: tell the rspm it's an orphan, but we can't during reload + // we need collect these and come back later to remove them + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Reload persistent event failed.\n") + )); + } + } + } + } + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Notify Service: Configuration error. Event Persistence requires Topology Persistence.\n") + )); + ACE_THROW (CORBA::PERSIST_STORE()); + ACE_CHECK; + } + } +#else //EVENT_PERISISTENCE_SUPPORT //@@todo +#pragma message ("TODO: EVENT_PERISISTENCE_SUPPORT") +#endif //EVENT_PERISISTENCE_SUPPORT //@@todo +} + +bool +TAO_Notify_EventChannelFactory::change_to_parent (ACE_ENV_SINGLE_ARG_DECL) +{ + bool saving = false; + if (! this->loading_topology_) + { + // A null pointer means that saving of topology is disabled. + if (this->topology_factory_ != 0) + { + saving = true; + // seq is used to check save-in-progress + // if it changes while we're waiting for the lock + // then our change may have already been saved, so + // just return. Caller will signal change again if necessary. + short seq = this->topology_save_seq_; + ACE_GUARD_THROW_EX (TAO_SYNCH_MUTEX, ace_mon, this->topology_save_lock_, CORBA::INTERNAL ()); + ACE_CHECK_RETURN(false); + if (seq == this->topology_save_seq_) + { + auto_ptr<TAO_NOTIFY::Topology_Saver> saver(this->topology_factory_->create_saver()); + if (saver.get() != 0) + { + this->save_persistent(*saver ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(false); + saver->close (ACE_ENV_SINGLE_ARG_PARAMETER); + } + this->topology_save_seq_ += 1; + } + } + } + return saving; +} + +TAO_NOTIFY::Topology_Object* +TAO_Notify_EventChannelFactory::load_child (const ACE_CString& type, + CORBA::Long id, + const TAO_NOTIFY:: + NVPList& attrs + ACE_ENV_ARG_DECL) +{ + // ignore anything but our valid children (ie channel) + TAO_NOTIFY::Topology_Object * result = this; + if (type == "channel") + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) EventChannelFactory reload channel %d\n") + , ACE_static_cast (int, id) + )); + + TAO_Notify_Builder* bld = TAO_Notify_PROPERTIES::instance()->builder(); + TAO_Notify_EventChannel * ec = bld->build_event_channel( + this , + id + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + + ec->load_attrs (attrs); + + result = ec; + } + else if (type == TAO_NOTIFY::REGISTRY_TYPE) + { + result = & this->reconnect_registry_; + } + return result; +} + +void +TAO_Notify_EventChannelFactory::reconnect (ACE_ENV_SINGLE_ARG_DECL) +{ + // Reconnect all children first + TAO_NOTIFY::Reconnect_Worker<TAO_Notify_EventChannel> wrk; + + this->ec_container_->collection()->for_each(&wrk ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + // Then send reconnection announcement to registered clients + CORBA::Object_var obj = this->poa()->id_to_reference (this->id () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + CosNotifyChannelAdmin::EventChannelFactory_var this_reference = CosNotifyChannelAdmin::EventChannelFactory::_narrow (obj.in ()); + ACE_ASSERT (CORBA::is_nil (this_reference.in ())); + // todo: Is there an easier way? + this->reconnect_registry_.send_reconnect (this_reference.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + +#ifdef TODO_EVENT_PERSISTENCE // + // reactivate events in-progress + Routing_Slip_Set::CONST_ITERATOR iter (this->routing_slip_restart_set_); + Routing_Slip_Ptr * routing_slip; + for (iter.first(); iter.next(routing_slip); iter.advance()) + { + (*routing_slip)->reconnect(ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + } + this->routing_slip_restart_set_.reset (); +#else + int TODO_Event_Persistence; +#endif +} + +NotifyExt::ReconnectionRegistry::ReconnectionID +TAO_Notify_EventChannelFactory::register_callback ( + NotifyExt::ReconnectionCallback_ptr reconnection + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + return this->reconnect_registry_.register_callback ( + reconnection + ACE_ENV_ARG_PARAMETER); +} + +void +TAO_Notify_EventChannelFactory::unregister_callback ( + NotifyExt::ReconnectionRegistry::ReconnectionID id + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + this->reconnect_registry_.unregister_callback ( + id + ACE_ENV_ARG_PARAMETER); +} + +CORBA::Boolean +TAO_Notify_EventChannelFactory::is_alive (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + return CORBA::Boolean (1); +} + +void +TAO_Notify_EventChannelFactory::save_topology (ACE_ENV_SINGLE_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; +} + #if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) template class TAO_Notify_Find_Worker_T<TAO_Notify_EventChannel diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.h b/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.h index c93fffd92a2..df2578bd4ea 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.h +++ b/TAO/orbsvcs/orbsvcs/Notify/EventChannelFactory.h @@ -22,8 +22,10 @@ #include "orbsvcs/CosNotifyChannelAdminS.h" #include "orbsvcs/NotifyExtS.h" - -#include "Object.h" +#include "Topology_Object.h" +#include "Topology_Factory.h" +#include "Reconnection_Registry.h" +//@@todo #include "Routing_Slip.h" class TAO_Notify_EventChannel; template <class TYPE> class TAO_Notify_Container_T; @@ -41,11 +43,13 @@ template <class TYPE> class TAO_Notify_Container_T; * @brief Implementation of CosNotifyChannelAdmin::EventChannelFactory * */ -class TAO_Notify_Serv_Export TAO_Notify_EventChannelFactory - : public virtual POA_NotifyExt::EventChannelFactory, - public virtual TAO_Notify_Object +class TAO_Notify_Serv_Export TAO_Notify_EventChannelFactory + : public virtual POA_NotifyExt::EventChannelFactory + , public TAO_NOTIFY::Topology_Parent + { friend class TAO_Notify_Builder; +//@@todo typedef ACE_Unbounded_Set <TAO_NOTIFY::Routing_Slip_Ptr> Routing_Slip_Set; public: /// Constuctor @@ -72,11 +76,42 @@ public: ACE_ENV_SINGLE_ARG_DECL ); - /// shutdown - virtual int shutdown (ACE_ENV_SINGLE_ARG_DECL); + + ////////////////////////// + // The following methods are for + // unit testing and debugging + + /// Use the registered Topology_Factory to create a loader, and + /// load the topology. If no Topology_Factory is registered + /// then nothing will be loaded. + void load_topology (ACE_ENV_SINGLE_ARG_DECL); + + /// Use the passed in saver factory to generate topology saver objects. + /// Does not take ownership. + void set_topology_factory(TAO_NOTIFY::Topology_Factory* sf); + + //-- Topology_Parent + + virtual bool is_persistent () const; + + virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL); + virtual bool change_to_parent (ACE_ENV_SINGLE_ARG_DECL); + virtual TAO_NOTIFY::Topology_Object* load_child (const ACE_CString &type, + CORBA::Long id, + const TAO_NOTIFY::NVPList& attrs + ACE_ENV_ARG_DECL); + virtual void reconnect (ACE_ENV_SINGLE_ARG_DECL); + + /// handle change notifications + bool handle_change (ACE_ENV_SINGLE_ARG_DECL); + + void load_event_persistence (ACE_ENV_SINGLE_ARG_DECL); + + virtual void save_topology (ACE_ENV_SINGLE_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); protected: - typedef TAO_Notify_Container_T<TAO_Notify_EventChannel> + typedef TAO_Notify_Container_T<TAO_Notify_EventChannel> TAO_Notify_EventChannel_Container; /// = Data Members @@ -86,21 +121,38 @@ public: /// The default filter factory. CosNotifyFilter::FilterFactory_var default_filter_factory_; - /// = NotifyExt method + /// = NotifyExt methods virtual void destroy (ACE_ENV_SINGLE_ARG_DECL) ACE_THROW_SPEC (( CORBA::SystemException )); + /// shutdown + virtual int shutdown (ACE_ENV_SINGLE_ARG_DECL); + + virtual + NotifyExt::ReconnectionRegistry::ReconnectionID register_callback ( + NotifyExt::ReconnectionCallback_ptr reconnection + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + + virtual void unregister_callback ( + NotifyExt::ReconnectionRegistry::ReconnectionID id + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + + virtual CORBA::Boolean is_alive (ACE_ENV_SINGLE_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + /// = CosNotifyChannelAdmin Methods virtual ::CosNotifyChannelAdmin::EventChannel_ptr create_channel ( const CosNotification::QoSProperties & initial_qos, const CosNotification::AdminProperties & initial_admin, - CosNotifyChannelAdmin::ChannelID_out id + CosNotifyChannelAdmin::ChannelID_out id ACE_ENV_ARG_DECL ) - ACE_THROW_SPEC ((CORBA::SystemException, + ACE_THROW_SPEC ((CORBA::SystemException, CosNotification::UnsupportedQoS, CosNotification::UnsupportedAdmin)); @@ -115,6 +167,17 @@ public: ) ACE_THROW_SPEC ((CORBA::SystemException, CosNotifyChannelAdmin::ChannelNotFound)); + +private: + TAO_SYNCH_MUTEX topology_save_lock_; + /// change-in-progress detector to avoid duplicates + short topology_save_seq_; + TAO_NOTIFY::Topology_Factory* topology_factory_; + TAO_NOTIFY::Reconnection_Registry reconnect_registry_; + bool loading_topology_; + +//@@todo Routing_Slip_Set routing_slip_restart_set_; + }; #if defined(_MSC_VER) && (_MSC_VER >= 1200) diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventType.cpp b/TAO/orbsvcs/orbsvcs/Notify/EventType.cpp index bcfae54e616..3f51adfdaf8 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/EventType.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/EventType.cpp @@ -10,6 +10,8 @@ #include "EventType.inl" #endif /* __ACE_INLINE__ */ +#include "Topology_Saver.h" + ACE_RCSID (Notify, TAO_Notify_EventType, "$Id$") @@ -139,3 +141,36 @@ TAO_Notify_EventType::dump (void) const this->event_type_.domain_name.in (), this->event_type_.type_name.in ())); } + +/// Initialize from an NVPList, return false on failure +bool TAO_Notify_EventType::init(const TAO_NOTIFY::NVPList& attrs) +{ + bool result = false; + + ACE_CString domain; + ACE_CString type; + if (attrs.load("Domain", domain) && attrs.load("Type", type)) + { + this->init_i(domain.c_str(), type.c_str()); + result = true; + } + return result; + +} + + // TAO_NOTIFY::Topology_Object + +void +TAO_Notify_EventType::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL) +{ + TAO_NOTIFY::NVPList attrs; + bool changed = true; + + attrs.push_back(TAO_NOTIFY::NVP("Domain", this->event_type_.domain_name.in())); + attrs.push_back(TAO_NOTIFY::NVP("Type", this->event_type_.type_name.in())); + saver.begin_object(0, "subscription", attrs, changed ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + saver.end_object(0, "subscription" ACE_ENV_ARG_PARAMETER); + ACE_CHECK; +} diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventType.h b/TAO/orbsvcs/orbsvcs/Notify/EventType.h index 3fcd875060d..7b76d7c78b0 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/EventType.h +++ b/TAO/orbsvcs/orbsvcs/Notify/EventType.h @@ -21,6 +21,7 @@ #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "orbsvcs/CosNotificationC.h" +#include "Topology_Object.h" /** * @class TAO_Notify_EventType @@ -31,7 +32,7 @@ * It is used by the Event Manager as a key to find subscription lists. * */ -class TAO_Notify_Serv_Export TAO_Notify_EventType +class TAO_Notify_Serv_Export TAO_Notify_EventType : public TAO_NOTIFY::Topology_Savable { public: /// Constuctor @@ -70,6 +71,13 @@ public: /// Helper to print contents. void dump (void) const; + /// Initialize from an NVPList, return false on failure + bool init(const TAO_NOTIFY::NVPList& attrs); + + // TAO_NOTIFY::Topology_Object + + virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL); + protected: /// Init this object. void init_i (const char* domain_name, const char* type_name); diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.cpp b/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.cpp index 5161da17add..b0fe9d65c53 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.cpp @@ -6,6 +6,12 @@ #include "EventTypeSeq.inl" #endif /* __ACE_INLINE__ */ +#include "Topology_Saver.h" + +#include "TAO/debug.h" +//#define DEBUG_LEVEL 9 +#define DEBUG_LEVEL TAO_debug_level + ACE_RCSID(Notify, TAO_Notify_EventTypeSeq, "$Id$") TAO_Notify_EventTypeSeq::TAO_Notify_EventTypeSeq (void) @@ -238,3 +244,71 @@ TAO_Notify_EventTypeSeq::dump (void) const ACE_DEBUG ((LM_DEBUG, ", ")); } } + + // TAO_NOTIFY::Topology_Object +void +TAO_Notify_EventTypeSeq::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL) +{ + bool changed = this->self_changed_; + this->self_changed_ = false; + this->children_changed_ = false; + TAO_NOTIFY::NVPList attrs; + + TAO_Notify_EventTypeSeq::ITERATOR iter (*this); + TAO_Notify_EventType* event_type; + + if (this->size() != 0) + { + saver.begin_object(0, "subscriptions", attrs, changed ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + for (iter.first (); iter.next (event_type) != 0; iter.advance ()) + { + event_type->save_persistent(saver ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } +// todo: +// for all deleted children +// { +// saver.delete_child(child_type, child_id); +// } + saver.end_object(0, "subscriptions" ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } +} + +TAO_NOTIFY::Topology_Object* +TAO_Notify_EventTypeSeq::load_child (const ACE_CString &type, CORBA::Long id, + const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL) +{ + TAO_NOTIFY::Topology_Object *result = this; + TAO_Notify_EventType et; + + if ((type == "subscription") && et.init(attrs)) + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Event_Type reload subscription\n") + )); + inherited::insert(et); + } + return result; +} + +void +TAO_Notify_EventTypeSeq::release (void) +{ + delete this; +} + +TAO_Notify_EventTypeSeq & +TAO_Notify_EventTypeSeq::operator = (const TAO_Notify_EventTypeSeq & rhs) +{ + ACE_Unbounded_Set <TAO_Notify_EventType>::operator = (rhs); + return *this; +} + +TAO_Notify_EventTypeSeq::TAO_Notify_EventTypeSeq (const TAO_Notify_EventTypeSeq & rhs) + : ACE_Unbounded_Set <TAO_Notify_EventType> (rhs) +{ +} + + diff --git a/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.h b/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.h index 9f492e605e7..09e0b0ca3c9 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.h +++ b/TAO/orbsvcs/orbsvcs/Notify/EventTypeSeq.h @@ -28,7 +28,10 @@ * @brief Allows operations using the CosNotification::EventTypeSeq type. * */ -class TAO_Notify_Serv_Export TAO_Notify_EventTypeSeq : public ACE_Unbounded_Set <TAO_Notify_EventType> +class TAO_Notify_Serv_Export TAO_Notify_EventTypeSeq + : public ACE_Unbounded_Set <TAO_Notify_EventType> + , public TAO_NOTIFY::Topology_Object + { typedef ACE_Unbounded_Set <TAO_Notify_EventType> inherited; @@ -36,6 +39,8 @@ public: /// Constructor TAO_Notify_EventTypeSeq (void); TAO_Notify_EventTypeSeq (const CosNotification::EventTypeSeq& event_type_seq); + TAO_Notify_EventTypeSeq (const TAO_Notify_EventTypeSeq & rhs); + TAO_Notify_EventTypeSeq & operator = (const TAO_Notify_EventTypeSeq & rhs); /// Preprocess the types added and removed. void init (TAO_Notify_EventTypeSeq& added, TAO_Notify_EventTypeSeq& removed); @@ -64,6 +69,14 @@ public: /// Print the contents. void dump (void) const; + + // TAO_NOTIFY::Topology_Object + + virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL); + virtual TAO_NOTIFY::Topology_Object* load_child (const ACE_CString &type, CORBA::Long id, + const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL); + virtual void release (void); + }; #if defined (__ACE_INLINE__) diff --git a/TAO/orbsvcs/orbsvcs/Notify/Event_Manager.cpp b/TAO/orbsvcs/orbsvcs/Notify/Event_Manager.cpp index 9a03b6c3c96..ef8c778aa9d 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Event_Manager.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/Event_Manager.cpp @@ -76,7 +76,7 @@ void TAO_Notify_Event_Manager::connect (TAO_Notify_ProxyConsumer* proxy_consumer ACE_ENV_ARG_DECL) { this->supplier_map_->connect (proxy_consumer ACE_ENV_ARG_PARAMETER); - + ACE_CHECK; // Inform about subscription types. TAO_Notify_EventTypeSeq removed; proxy_consumer->types_changed (this->subscription_types (), removed ACE_ENV_ARG_PARAMETER); diff --git a/TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Factory.h b/TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Factory.h new file mode 100644 index 00000000000..61134f2d30e --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Factory.h @@ -0,0 +1,52 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Event_Persistence_Factory.h + * + * $Id$ + * + * A factory class that creates a Routing_Slip_Persistence_Manager. + * + * @author Jonathan Pollack <pollack_j@ociweb.com> + */ +//============================================================================= + +#ifndef EVENT_PERSISTENCE_FACTORY_H +#define EVENT_PERSISTENCE_FACTORY_H +#include /**/ "ace/pre.h" +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "notify_export.h" + +//#include "Event_Persistence_Strategy.h" +//#include "Persistent_File_Allocator.h" +//#include "Routing_Slip_Persistence_Manager.h" +//#include <ace/SString.h> + +namespace TAO_NOTIFY +{ + class Routing_Slip_Persistence_Manager; + class Persistent_Callback; + + /// interface to be implemented by specific Event_Persistence_Factories + class TAO_Notify_Export Event_Persistence_Factory + { + public: + /// Create a Persistence Manager + virtual Routing_Slip_Persistence_Manager * + create_routing_slip_persistence_manager (Persistent_Callback * callback) = 0; + + /// Begin the reload process by returning the first Routing_Slip_Persistence_Manager + /// to continue call Routing_Slip_Persistence_Manager::load_next () + virtual Routing_Slip_Persistence_Manager * first_reload_manager () = 0; + + }; +} // namespace TAO_NOTIFY + +#include /**/ "ace/post.h" +#endif /* EVENT_PERSISTENCE_FACTORY_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Strategy.h b/TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Strategy.h new file mode 100644 index 00000000000..d2fcacf03c6 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Event_Persistence_Strategy.h @@ -0,0 +1,47 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Event_Persistence_Strategy.h + * + * $Id$ + * + * A factory class that creates a Routing_Slip_Persistence_Manager. + * + * @author Jonathan Pollack <pollack_j@ociweb.com> + */ +//============================================================================= + +#ifndef EVENT_PERSISTENCE_STRATEGY_H +#define EVENT_PERSISTENCE_STRATEGY_H +#include /**/ "ace/pre.h" +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "notify_export.h" + +#include "ace/Service_Object.h" + +namespace TAO_NOTIFY +{ + class Event_Persistence_Factory; + + /// Interface to be implemented by specific strategies + class TAO_Notify_Export Event_Persistence_Strategy: public ACE_Service_Object + { + public: + + // get the current factory, creating it if necessary + virtual Event_Persistence_Factory * get_factory () = 0; + + // release the current factory so a new one can be created + virtual void reset () = 0; + }; + +} // namespace TAO_NOTIFY + +#include /**/ "ace/post.h" +#endif /* EVENT_PERSISTENCE_STRATEGY_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.cpp b/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.cpp index d6b64275843..9ec4a1099de 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.cpp @@ -8,6 +8,8 @@ ACE_RCSID(Notify, FilterAdmin, "$Id$") +#include "Topology_Saver.h" +#include "Properties.h" #include "ace/Refcounted_Auto_Ptr.h" // Implementation skeleton constructor @@ -128,6 +130,76 @@ TAO_Notify_FilterAdmin::remove_all_filters (ACE_ENV_SINGLE_ARG_DECL) this->filter_list_.unbind_all (); } +void +TAO_Notify_FilterAdmin::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL) +{ + if (this->filter_list_.current_size() == 0) + return; + + bool changed = true; + + TAO_NOTIFY::NVPList attrs; + bool want_children = saver.begin_object(0, "filter_admin", attrs, changed ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + if (want_children) + { + FILTER_LIST::ITERATOR iter (this->filter_list_); + FILTER_LIST::ENTRY* entry; + + TAO_Notify_Properties* properties = TAO_Notify_PROPERTIES::instance(); + CORBA::ORB_var orb = properties->orb(); + ACE_ASSERT(! CORBA::is_nil(orb.in())); + + for (; iter.next(entry) != 0; iter.advance()) + { + TAO_NOTIFY::NVPList fattrs; + CORBA::Long id = entry->ext_id_; + CORBA::String_var ior = orb->object_to_string(entry->int_id_.in() ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + fattrs.push_back(TAO_NOTIFY::NVP("IOR", ior.in())); + saver.begin_object(id, "filter", fattrs, changed ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + saver.end_object(id, "filter" ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + } + + saver.end_object(0, "filter_admin" ACE_ENV_ARG_PARAMETER); +} + +TAO_NOTIFY::Topology_Object* +TAO_Notify_FilterAdmin::load_child (const ACE_CString &type, CORBA::Long id, + const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL) +{ + if (type == "filter") + { + TAO_Notify_Properties* properties = TAO_Notify_PROPERTIES::instance(); + CORBA::ORB_var orb = properties->orb(); + ACE_ASSERT(! CORBA::is_nil(orb.in())); + ACE_CString ior; + attrs.load("IOR", ior); + + CORBA::Object_var obj = orb->string_to_object(ior.c_str() ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + CosNotifyFilter::Filter_var filter = CosNotifyFilter::Filter::_unchecked_narrow(obj.in() ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + if (! CORBA::is_nil(filter.in())) + { + this->filter_ids_.set_last_used(id); + if (this->filter_list_.bind (id, filter) != 0) + ACE_THROW_RETURN (CORBA::INTERNAL (), 0); + } + } + return this; +} + +void +TAO_Notify_FilterAdmin::release (void) +{ + delete this; +} + + #if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) template class ACE_Hash_Map_Entry<CosNotifyFilter::FilterID,CosNotifyFilter::Filter_var>; template class ACE_Hash_Map_Manager<CosNotifyFilter::FilterID,CosNotifyFilter::Filter_var,ACE_Null_Mutex>; diff --git a/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.h b/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.h index 4e40b0b5ac9..04507e52599 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.h +++ b/TAO/orbsvcs/orbsvcs/Notify/FilterAdmin.h @@ -22,6 +22,7 @@ #include "ID_Factory.h" #include "Event.h" #include "notify_serv_export.h" +#include "Topology_Object.h" /** * @class TAO_Notify_FilterAdmin @@ -30,6 +31,7 @@ * */ class TAO_Notify_Serv_Export TAO_Notify_FilterAdmin + : public TAO_NOTIFY::Topology_Object { public: @@ -80,6 +82,13 @@ class TAO_Notify_Serv_Export TAO_Notify_FilterAdmin CORBA::SystemException )); + + // TAO_NOTIFY::Topology_Object + + virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL); + virtual TAO_NOTIFY::Topology_Object* load_child (const ACE_CString &type, CORBA::Long id, + const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL); + virtual void release (void); private: typedef ACE_Hash_Map_Manager <CosNotifyFilter::FilterID, CosNotifyFilter::Filter_var, ACE_SYNCH_NULL_MUTEX> FILTER_LIST; diff --git a/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.cpp b/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.cpp index 8e021520caf..b8bec81f68c 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.cpp @@ -9,6 +9,7 @@ ACE_RCSID(Notify, TAO_Notify_ID_Factory, "$Id$") TAO_Notify_ID_Factory::TAO_Notify_ID_Factory (void) + : seed_ (0) { } diff --git a/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.h b/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.h index f3f6e3127b0..b9f0bd8aef5 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.h +++ b/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.h @@ -41,8 +41,12 @@ public: TAO_Notify_Object::ID id (void); + void set_last_used (const TAO_Notify_Object::ID id); + private: - ACE_Atomic_Op<TAO_SYNCH_MUTEX, TAO_Notify_Object::ID> seed_; + // Can't use atomic op, because we added the set_last_used() method. + TAO_Notify_Object::ID seed_; + TAO_SYNCH_MUTEX mtx_; }; diff --git a/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.inl b/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.inl index 74a2d8582d6..f9fb1f5e89b 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.inl +++ b/TAO/orbsvcs/orbsvcs/Notify/ID_Factory.inl @@ -3,5 +3,16 @@ ACE_INLINE TAO_Notify_Object::ID TAO_Notify_ID_Factory::id (void) { + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, ace_mon, this->mtx_, 0); return ++seed_; } + +ACE_INLINE void +TAO_Notify_ID_Factory::set_last_used (const TAO_Notify_Object::ID id) +{ + ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->mtx_); + if (this->seed_ < id) + { + this->seed_ = id; + } +} diff --git a/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.cpp b/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.cpp new file mode 100644 index 00000000000..95baf13ee69 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.cpp @@ -0,0 +1,227 @@ +// $Id$ + +#include "Name_Value_Pair.h" + +#if ! defined (__ACE_INLINE__) +#include "Name_Value_Pair.inl" +#endif /* __ACE_INLINE__ */ + +#include "Property_T.h" +#include "ace/OS_String.h" +#include "ace/OS_NS_stdio.h" + +namespace +{ + ACE_UINT64 string_to_uint64(const char * s) + { + size_t len = ACE_OS::strlen (s); + if (len == 0) + return 0; + if (! isdigit(s[0])) + return 0; + + ACE_UINT64 t = 0; + for (size_t i = 0; i < len; ++i) + { + if (isdigit(s[i]) == 0) + { + break; + } + t *= 10; + t += (s[i] - '0'); + } + return t; + } +} + +namespace TAO_NOTIFY +{ + NVP::NVP() + { + } + + NVP::NVP(const TAO_Notify_Property_Short& p) + : name(p.name()) + { + char buf[64]; + ACE_OS::sprintf (buf, "%d", p.value ()); + value = buf; + } + + NVP::NVP(const TAO_Notify_Property_Long& p) + : name(p.name()) + { + char buf[64]; + long temp = ACE_static_cast (long, p.value ()); + ACE_OS::sprintf (buf, "%ld", temp); + value = buf; + } + + NVP::NVP(const TAO_Notify_Property_Time& p) + : name(p.name()) + { + char buf[128]; + ACE_UINT64 us = p.value(); +#ifdef ACE_LACKS_LONGLONG_T + us.as_string(buf); +#else + ACE_OS::sprintf(buf, ACE_UINT64_FORMAT_SPECIFIER, us); +#endif /* ACE_LACKS_LONGLONG_T */ + value = buf; + } + + NVP::NVP(const TAO_Notify_Property_Boolean& p) + : name(p.name()) + { + value = p.value() ? "true" : "false"; + } + + NVP::NVP(const char * n, CORBA::Long v) + : name(n) + { + char buf[64]; + long temp = v; + ACE_OS::sprintf (buf, "%ld", temp); + value = buf; + } + + NVP::NVP(const char * n, const char * v) + : name(n), value(v) + { + } + + NVP::NVP(const char * n, const ACE_CString & v) + : name(n), value(v) + { + } + + bool NVP::operator==(const NVP& rhs) const + { + return (this->name == rhs.name) != 0; + } + + bool NVP::operator!=(const NVP& rhs) const + { + return ! (rhs == *this); + } + + bool NVPList::find (const char * name, ACE_CString& val) const + { + for (size_t i = 0; i < list_.size(); ++i) + { + if (list_[i].name == name) + { + val = list_[i].value; + return true; + } + } + return false; + } + + bool NVPList::find (const char * name, const char *& val) const + { + for (size_t i = 0; i < list_.size(); ++i) + { + if (list_[i].name == name) + { + val = list_[i].value.c_str (); + return true; + } + } + return false; + } + + void NVPList::load(TAO_Notify_Property_Short& p) const + { + const char * v; + if (find(p.name(), v)) + { + p.assign (static_cast<CORBA::Short> (ACE_OS::atoi(v))); + } + } + + void NVPList::load(TAO_Notify_Property_Long& p) const + { + const char * v; + if (find(p.name(), v)) + { + p.assign (static_cast<CORBA::Long> (ACE_OS::atoi(v))); + } + } + + void NVPList::load(TAO_Notify_Property_Time& p) const + { + const char * v; + if (find(p.name (), v)) + { + p.assign (ACE_static_cast(TimeBase::TimeT, string_to_uint64(v))); + } + } + + void NVPList::load(TAO_Notify_Property_Boolean& p) const + { + ACE_CString v; + if (find(p.name (), v)) + { + if (v == "true") + { + p = 1; + } + else + { + p = 0; + } + } + } + + bool NVPList::load(const char * n, CORBA::Long& v) const + { + const char * val; + if (find(n, val)) + { + v = ACE_static_cast(CORBA::Long, ACE_OS::atoi(val)); + return true; + } + return false; + } + + bool NVPList::load(const char * n, ACE_CString& v) const + { + return find(n, v); + } + + void NVPList::push_back(const NVP& v) + { + for (size_t i = 0; i < list_.size(); ++i) + { + if (list_[i].name == v.name) + { + list_[i].value = v.value; + return; + } + } + list_.push_back(v); + } + + size_t NVPList::size() const + { + return list_.size(); + } + + const NVP& NVPList::operator[](size_t ndx) const + { + ACE_ASSERT(ndx < list_.size()); + return list_[ndx]; + } + +} // namespace TAO_NOTIFY + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +template class ACE_Array_Base<TAO_NOTIFY::NVP>; +template class ACE_Array<TAO_NOTIFY::NVP>; +template class ACE_Vector<TAO_NOTIFY::NVP>; +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#pragma instantiate ACE_Array_Base<TAO_NOTIFY::NVP> +#pragma instantiate ACE_Array<TAO_NOTIFY::NVP> +#pragma instantiate ACE_Vector<TAO_NOTIFY::NVP> +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.h b/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.h new file mode 100644 index 00000000000..59ee9b41b18 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.h @@ -0,0 +1,102 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** +* @file Name_Value_Pair.h +* +* $Id$ +* +* @author Jonathan Pollack <pollack_j@ociweb.com> +*/ +//============================================================================= + +#ifndef NAME_VALUE_PAIR_H +#define NAME_VALUE_PAIR_H +#include /**/ "ace/pre.h" + +#include "Property.h" +#include "Property_Boolean.h" +#include "notify_export.h" + +#include "ace/SString.h" +#include "ace/Vector_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace TAO_NOTIFY +{ + /** + * \brief Name/Value Pair + * + * Associates a name (character string) with a value (encoded into a character string) + * For use in managing properties. + */ + class TAO_Notify_Serv_Export NVP { + public: + /// Construct an undefined name/value (to allow use in collections) + NVP(); + /// Construct from a property containing a short value. + explicit NVP(const TAO_Notify_Property_Short& p); + /// Construct from a property containing a long value. + explicit NVP(const TAO_Notify_Property_Long& p); + /// Construct from a property containing a time value + explicit NVP(const TAO_Notify_Property_Time& p); + /// Construct from a property containing a boolean value + explicit NVP(const TAO_Notify_Property_Boolean& p); + + /// Construct from name and long value. + NVP(const char * n, CORBA::Long v); + /// Construct from name and string value. + NVP(const char * n, const char * v); + /// Construct from name and string value. + NVP(const char * n, const ACE_CString & v); + + /// Assignment operator + bool operator==(const NVP& rhs) const; + /// Comparison operator compares only name (not value) + bool operator!=(const NVP& rhs) const; + ACE_CString name; + ACE_CString value; + }; + + /** + * \brief Collection of Name/Value Pairs + */ + class TAO_Notify_Serv_Export NVPList { + public: + /// Find the NVP with the same name as the property, copy the value. + void load(TAO_Notify_Property_Short& p) const; + /// Find the NVP with the same name as the property, copy the value. + void load(TAO_Notify_Property_Long& p) const; + /// Find the NVP with the same name as the property, copy the value. + void load(TAO_Notify_Property_Time& p) const; + /// Find the NVP with the same name as the property, copy the value. + void load(TAO_Notify_Property_Boolean& p) const; + /// Find the NVP with specified name, copy the value to a string. + bool load(const char * n, CORBA::Long& v) const; + /// Find the NVP with specified name, copy the value to a long. + bool load(const char * n, ACE_CString& v) const; + /// add a new name/value pair. + void push_back(const NVP& v); + /// size of the collection. + size_t size() const; + /// access NVP via numeric index. + const NVP& operator[](size_t ndx) const; + /// low level access: find + bool find (const char * name, ACE_CString& val) const; + /// low level access: use this when you don't need a CString + bool find (const char * name, const char *& val) const; + + private: + ACE_Vector<NVP> list_; + }; +} // namespace TAO_NOTIFY + +#if defined (__ACE_INLINE__) +#include "Name_Value_Pair.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* NAME_VALUE_PAIR_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.inl b/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.inl new file mode 100644 index 00000000000..cfa1da318d3 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Name_Value_Pair.inl @@ -0,0 +1 @@ +// $Id$ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Object.cpp b/TAO/orbsvcs/orbsvcs/Notify/Object.cpp index 49c9b9b07a1..6ad873f70ab 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Object.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/Object.cpp @@ -15,6 +15,8 @@ ACE_RCSID(Notify, TAO_Notify_Object, "$Id$") + + TAO_Notify_Object::TAO_Notify_Object (void) : event_manager_ (0) , admin_properties_ (0) @@ -66,6 +68,18 @@ TAO_Notify_Object::activate (PortableServer::Servant servant ACE_ENV_ARG_DECL) return this->poa_->activate (servant, this->id_ ACE_ENV_ARG_PARAMETER); } +/// Activate with existing id +CORBA::Object_ptr +TAO_Notify_Object::activate ( + PortableServer::Servant servant, + CORBA::Long id + ACE_ENV_ARG_DECL) +{ + this->id_ = id; + return this->poa_->activate_with_id (servant, this->id_ ACE_ENV_ARG_PARAMETER); +} + + void TAO_Notify_Object::deactivate (ACE_ENV_SINGLE_ARG_DECL) { @@ -77,10 +91,10 @@ TAO_Notify_Object::deactivate (ACE_ENV_SINGLE_ARG_DECL) ACE_CATCHANY { if (TAO_debug_level > 2) - { - ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, "(%P|%t)\n"); - ACE_DEBUG ((LM_DEBUG, "Could not deactivate object %d\n", this->id_)); - } + { + ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, "(%P|%t)\n"); + ACE_DEBUG ((LM_DEBUG, "Could not deactivate object %d\n", this->id_)); + } // Do not propagate any exceptions } ACE_ENDTRY; @@ -133,7 +147,7 @@ TAO_Notify_Object::shutdown_proxy_poa (void) { this->proxy_poa_->destroy (ACE_ENV_SINGLE_ARG_PARAMETER); ACE_TRY_CHECK; - + delete this->proxy_poa_; } ACE_CATCHANY @@ -268,6 +282,15 @@ TAO_Notify_Object::get_qos (ACE_ENV_SINGLE_ARG_DECL) return properties._retn (); } +bool +TAO_Notify_Object::find_qos_property_value ( + const char * name, + CosNotification::PropertyValue & value) const +{ + return this->qos_properties_.find (name, value); +} + + void TAO_Notify_Object::qos_changed (const TAO_Notify_QoSProperties& /*qos_properties*/) { @@ -279,3 +302,60 @@ TAO_Notify_Object::timer (void) { return this->worker_task_->timer (); } + +namespace { + template<class T> + void add_qos_attr(TAO_NOTIFY::NVPList& attrs, const T& prop) { + if (prop.is_valid()) + { + attrs.push_back(TAO_NOTIFY::NVP (prop)); + } + } +// Note : These instantiations have to be here because each namespace {} +// is unique. +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +template void add_qos_attr<TAO_Notify_Property_Boolean>( + TAO_NOTIFY::NVPList&, const TAO_Notify_Property_Boolean&); +template void add_qos_attr<TAO_Notify_Property_T<int> >( + TAO_NOTIFY::NVPList&, const TAO_Notify_Property_T<int>&); +template void add_qos_attr<TAO_Notify_Property_T<unsigned long long> >( + TAO_NOTIFY::NVPList&, const TAO_Notify_Property_T<unsigned long long>&); +template void add_qos_attr<TAO_Notify_Property_T<short> >( + TAO_NOTIFY::NVPList&, const TAO_Notify_Property_T<short>&); +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#pragma instantiate void add_qos_attr<TAO_Notify_Property_Boolean>(\ + TAO_NOTIFY::NVPList&, const TAO_Notify_Property_Boolean&) +#pragma instantiate void add_qos_attr<TAO_Notify_Property_T<int> >(\ + TAO_NOTIFY::NVPList&, const TAO_Notify_Property_T<int>&) +#pragma instantiate void add_qos_attr<TAO_Notify_Property_T<unsigned long long> >(\ + TAO_NOTIFY::NVPList&, const TAO_Notify_Property_T<unsigned long long>&) +#pragma instantiate void add_qos_attr<TAO_Notify_Property_T<short> >(\ + TAO_NOTIFY::NVPList&, const TAO_Notify_Property_T<short>&) +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ +} // namespace + +void +TAO_Notify_Object::save_attrs (TAO_NOTIFY::NVPList& attrs) +{ + add_qos_attr(attrs, this->qos_properties_.event_reliability ()); + add_qos_attr(attrs, this->qos_properties_.connection_reliability ()); + add_qos_attr(attrs, this->qos_properties_.priority ()); + add_qos_attr(attrs, this->qos_properties_.timeout ()); + add_qos_attr(attrs, this->qos_properties_.stop_time_supported ()); + add_qos_attr(attrs, this->qos_properties_.maximum_batch_size ()); + add_qos_attr(attrs, this->qos_properties_.pacing_interval ()); +} + +void +TAO_Notify_Object::load_attrs(const TAO_NOTIFY::NVPList& attrs) +{ + attrs.load (this->qos_properties_.event_reliability ()); + attrs.load (this->qos_properties_.connection_reliability ()); + attrs.load (this->qos_properties_.priority ()); + attrs.load (this->qos_properties_.timeout ()); + attrs.load (this->qos_properties_.stop_time_supported ()); + attrs.load (this->qos_properties_.maximum_batch_size ()); + attrs.load (this->qos_properties_.pacing_interval ()); + this->qos_properties_.init (); +} + diff --git a/TAO/orbsvcs/orbsvcs/Notify/Object.h b/TAO/orbsvcs/orbsvcs/Notify/Object.h index cf1f1044fac..7c95ea99c07 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Object.h +++ b/TAO/orbsvcs/orbsvcs/Notify/Object.h @@ -27,6 +27,7 @@ #include "QoSProperties.h" #include "AdminProperties.h" #include "Refcountable.h" +#include "Name_Value_Pair.h" class TAO_Notify_POA_Helper; class TAO_Notify_Worker_Task; @@ -54,11 +55,17 @@ public: virtual ~TAO_Notify_Object (void); /// This Object's ID - ID id (void); + ID id (void) const; /// Activate virtual CORBA::Object_ptr activate (PortableServer::Servant servant ACE_ENV_ARG_DECL); + /// Activate with existing id + virtual CORBA::Object_ptr activate ( + PortableServer::Servant servant, + CORBA::Long id + ACE_ENV_ARG_DECL); + /// Deactivate void deactivate (ACE_ENV_SINGLE_ARG_DECL); @@ -98,6 +105,10 @@ public: /// Get the QoS Properties. CosNotification::QoSProperties* get_qos (ACE_ENV_SINGLE_ARG_DECL); + bool find_qos_property_value ( + const char * name, + CosNotification::PropertyValue & value)const; + /// Obtain the Timer manager associated with this object. virtual TAO_Notify_Timer* timer (void); @@ -107,6 +118,10 @@ public: /// Accessor for the Event Manager TAO_Notify_Event_Manager* event_manager (void); + /// Load our attributes. Each derived type should call the superclass + /// load first before loading its own attributes. + virtual void load_attrs(const TAO_NOTIFY::NVPList& attrs); + protected: /// Init this object with data from <rhs>. void init (TAO_Notify_Object* parent); @@ -123,6 +138,11 @@ protected: /// Notification that can be overridden by subclasses to be informed that <qos_properties_> have been modified. virtual void qos_changed (const TAO_Notify_QoSProperties& qos_properties); + /// Called by derived types to save their attributes. Each + /// derived type should call its superclass version before + /// saving its own attrs. + virtual void save_attrs(TAO_NOTIFY::NVPList& attrs); + ///= Protected data members. /// The event manager. diff --git a/TAO/orbsvcs/orbsvcs/Notify/Object.inl b/TAO/orbsvcs/orbsvcs/Notify/Object.inl index 9ba8797906a..3a20131bbec 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Object.inl +++ b/TAO/orbsvcs/orbsvcs/Notify/Object.inl @@ -1,7 +1,7 @@ // $Id$ ACE_INLINE CORBA::Long -TAO_Notify_Object::id (void) +TAO_Notify_Object::id (void) const { return id_; } diff --git a/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.cpp b/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.cpp index fd0182a8dfc..95817d46083 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.cpp @@ -148,6 +148,26 @@ TAO_Notify_POA_Helper::activate (PortableServer::Servant servant, CORBA::Long& i ACE_ENV_ARG_PARAMETER); } +CORBA::Object_ptr +TAO_Notify_POA_Helper::activate_with_id (PortableServer::Servant servant, CORBA::Long id ACE_ENV_ARG_DECL) +{ + if (TAO_debug_level > 0) + ACE_DEBUG ((LM_DEBUG, "Activating object with existing id = %d in POA : %s\n", id, this->poa_->the_name ())); + + // Convert CORBA::Long to ObjectId + PortableServer::ObjectId_var oid = + this->long_to_ObjectId (id ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (CORBA::Object::_nil ()); + + poa_->activate_object_with_id (oid.in (), + servant + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (CORBA::Object::_nil ()); + + return poa_->id_to_reference (oid.in () + ACE_ENV_ARG_PARAMETER); +} + void TAO_Notify_POA_Helper::deactivate (CORBA::Long id ACE_ENV_ARG_DECL) const { @@ -171,6 +191,20 @@ TAO_Notify_POA_Helper::id_to_reference (CORBA::Long id ACE_ENV_ARG_DECL) const ACE_ENV_ARG_PARAMETER); } +PortableServer::ServantBase * +TAO_Notify_POA_Helper::reference_to_servant (CORBA::Object_ptr ptr ACE_ENV_ARG_DECL) const +{ + return poa_->reference_to_servant (ptr ACE_ENV_ARG_PARAMETER); +} + +CORBA::Object_ptr +TAO_Notify_POA_Helper::servant_to_reference ( + PortableServer::ServantBase * servant ACE_ENV_ARG_DECL) const +{ + return poa_->servant_to_reference (servant ACE_ENV_ARG_PARAMETER); +} + + void TAO_Notify_POA_Helper::destroy (ACE_ENV_SINGLE_ARG_DECL) { diff --git a/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.h b/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.h index 831b0dc163d..bd3e0ed6a38 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.h +++ b/TAO/orbsvcs/orbsvcs/Notify/POA_Helper.h @@ -54,12 +54,20 @@ public: /// Activate Object, the POA will assign an ID and return its value. CORBA::Object_ptr activate (PortableServer::Servant servant, CORBA::Long& id ACE_ENV_ARG_DECL); + /// Activate Object, using existing ID + CORBA::Object_ptr activate_with_id (PortableServer::Servant servant, CORBA::Long id ACE_ENV_ARG_DECL); + /// Deactivate Object with ID void deactivate (CORBA::Long id ACE_ENV_ARG_DECL) const; /// Convert ID to reference. CORBA::Object_ptr id_to_reference (CORBA::Long id ACE_ENV_ARG_DECL) const; + /// Convert reference to pointer to servant + PortableServer::ServantBase * reference_to_servant (CORBA::Object_ptr ptr ACE_ENV_ARG_DECL) const; + + CORBA::Object_ptr servant_to_reference (PortableServer::ServantBase * servant ACE_ENV_ARG_DECL) const; + protected: /// Set default POA policies. virtual void set_policy (PortableServer::POA_ptr parent_poa, CORBA::PolicyList &policy_list ACE_ENV_ARG_DECL); diff --git a/TAO/orbsvcs/orbsvcs/Notify/Peer.h b/TAO/orbsvcs/orbsvcs/Notify/Peer.h index deaf6fc66ea..5778281bc71 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Peer.h +++ b/TAO/orbsvcs/orbsvcs/Notify/Peer.h @@ -66,6 +66,9 @@ public: /// Handle dispatch exceptions. void handle_dispatch_exception (ACE_ENV_SINGLE_ARG_DECL); + /// Retrieve the ior of this peer + virtual bool get_ior (ACE_CString & iorstr) const = 0; + protected: /// Implementation of Peer specific dispatch_updates virtual void dispatch_updates_i (const CosNotification::EventTypeSeq& added, diff --git a/TAO/orbsvcs/orbsvcs/Notify/Persistent_File.cpp b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File.cpp new file mode 100644 index 00000000000..e133e60c671 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File.cpp @@ -0,0 +1,158 @@ +// $Id$ + +#include "Persistent_File.h" + +#include "ace/OS.h" +#include <tao/debug.h> +//#define DEBUG_LEVEL 9 // uncomment to force debug messages +#define DEBUG_LEVEL TAO_debug_level // coment to force debug messages + +namespace TAO_NOTIFY +{ + +Persistent_File::Persistent_File() + : block_size_(512) +{ +} + +Persistent_File::~Persistent_File() +{ + this->close(); +} + +size_t +Persistent_File::block_size() const +{ + return this->block_size_; +} + +size_t +Persistent_File::size() const +{ + Persistent_File * mutable_this = ACE_const_cast (Persistent_File *, this); + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, mutable_this->lock_, 0); + size_t original_pos = mutable_this->tell (); + mutable_this->ACE_FILE::seek(0, SEEK_END); + size_t cursize = mutable_this->tell(); + mutable_this->ACE_FILE::seek (original_pos, SEEK_SET); + if ((cursize % this->block_size_) != 0) + { + cursize += this->block_size_; + } + return cursize / this->block_size_; +} + +bool +Persistent_File::open(const char* filename, size_t block_size) +{ + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, false); + this->block_size_ = block_size; + bool result = (this->close() == 0); + + if (result) + { + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Opening file %s\n") + , filename + )); + ACE_HANDLE handle = ACE_OS::open(filename, + O_CREAT | O_RDWR | O_BINARY, + ACE_DEFAULT_FILE_PERMS); + + if (handle == ACE_INVALID_HANDLE) + { + result = false; + } + else + { + this->set_handle(handle); + if (this->get_handle() == 0) + { + result = false; + } + else + { + result = (this->addr_.set(filename) == 0); + } + } + } + return result; +} + +bool +Persistent_File::write(const size_t block_number, void* buf, bool atomic) +{ + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, false); + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Write block %d %c\n"), + ACE_static_cast (int, block_number), + (atomic ? '*' : ' ') + )); + bool result = this->seek(block_number); + if (result) + { + if (atomic) + { + // sync before so that any block pointed to from this block + // will be there when this block is written. + result = sync(); + } + // ACE uses an ssize_t for buffer size, so we do this to make it happy. + ssize_t block_size = this->block_size_; + if (result && (block_size != + ACE_OS::write(this->get_handle(), buf, block_size))) + { + result = false; + } + if (result && atomic) + { + // sync after to provide the caller with a guarantee that + // this block is physically written to the storage device. + result = sync(); + } + } + return result; +} + +bool +Persistent_File::read(const size_t block_number, void* buf) +{ + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, false); + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Read block %d\n"), + ACE_static_cast (int, block_number) + )); + bool result = this->seek(block_number); + if (result) + { + ssize_t block_size = this->block_size_; + if (block_size != + ACE_OS::read(this->get_handle(), buf, block_size)) + { + result = false; + } + } + return result; +} + +bool +Persistent_File::seek(const size_t block_number) +{ + ssize_t destloc = block_number * this->block_size_; + bool result = (destloc == this->ACE_FILE::seek(destloc, SEEK_SET)); + return result; +} + +bool +Persistent_File::sync() +{ + bool result = false; + result = (0 == ACE_OS::fsync(this->get_handle())); + return result; +} + +} /* namespace TAO_NOTIFY */ + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Persistent_File.h b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File.h new file mode 100644 index 00000000000..f04ce0108ab --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File.h @@ -0,0 +1,89 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Persistent_File.h + * + * $Id$ + * + * This class implements a a random-access file containing + * fixed-size blocks. + * + * @author Jonathan Pollack <pollack_j@ociweb.com> + */ +//============================================================================= + +#ifndef PERSISTENT_FILE_H +#define PERSISTENT_FILE_H +#include /**/ "ace/pre.h" +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "notify_export.h" +#include "ace/FILE.h" +#include "ace/streams.h" +#include "ace/Synch_T.h" + +namespace TAO_NOTIFY +{ + +/** + * \brief A persistent file class. + * + * Derived from ACE_FILE, this class provides access to a + * file of fixed-size blocks. + * + */ +class TAO_Notify_Export Persistent_File : public ACE_FILE +{ +public: + /// The constructor. + Persistent_File(); + + /// The destructor, which closes the open file. + ~Persistent_File(); + + /// Open a file with default permissions. + bool open(const char* filename, size_t block_size = 512); + + /// Accessor for the block size. + /// Note signed size_t is used to be compatible with + /// ACE_FILE. + size_t block_size() const; + + /// Return the current file size, in number of blocks. + size_t size() const; + + /// Write a block to our file, potentially as an "atomic" write. + /// If the atomic argument is true, then the operating system's + /// write-through cache for this file is flushed both before and + /// after the write. + /// The flush before ensures that any record pointers in this block + /// will point to records that actually appear in the file. + /// The flush after provides the caller with a guarantee that + /// the data will appear in the file even if the system fails + /// immediately after this method returns. + bool write(const size_t block_number, void* buffer, bool atomic = false); + + /// Read a block from our file. + bool read(const size_t block_number, void* buffer); + +private: + /// Seek to a given block number, used by reads and writes. + bool seek(const size_t block_number); + + /// Synchronize the file to disk, used to implement atomic. + bool sync(); + +private: + size_t block_size_; + ACE_SYNCH_MUTEX lock_; +}; + +} /* namespace TAO_NOTIFY */ + +#include /**/ "ace/post.h" +#endif /* PERSISTENT_FILE_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.cpp b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.cpp new file mode 100644 index 00000000000..d5206fd5042 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.cpp @@ -0,0 +1,401 @@ +// $Id$ + +#include "Persistent_File_Allocator.h" + +#include <tao/debug.h> +#include "ace/OS_NS_string.h" + +//#define DEBUG_LEVEL 9 +#define DEBUG_LEVEL TAO_debug_level + +namespace TAO_NOTIFY +{ + +Persistent_Storage_Block::Persistent_Storage_Block(const size_t block_number, + const size_t block_size) + : block_number_(block_number) + , no_write_(false) + , sync_(false) + , block_size_(block_size) + , callback_(0) + , allocator_owns_(true) +{ + ACE_NEW(this->data_, unsigned char[this->block_size_]); + ACE_OS::memset(this->data_, 0, this->block_size_); + +} + +Persistent_Storage_Block::Persistent_Storage_Block( + const Persistent_Storage_Block& psb) + : block_number_(psb.block_number_) + , no_write_(psb.no_write_) + , sync_(psb.sync_) + , block_size_(psb.block_size_) + , callback_(psb.callback_) + , allocator_owns_(psb.allocator_owns_) +{ + ACE_NEW(this->data_, unsigned char[this->block_size_]); + ACE_OS::memcpy(this->data_, psb.data(), this->block_size_); +} + +Persistent_Storage_Block::~Persistent_Storage_Block() +{ + delete [] this->data_; + this->data_ = 0; +} + +void +Persistent_Storage_Block::set_no_write() +{ + this->no_write_ = true; + this->reassign_data(0, true); +} + +bool +Persistent_Storage_Block::get_no_write() +{ + return this->no_write_; +} + +void +Persistent_Storage_Block::set_sync() +{ + this->sync_ = true; +} + +bool +Persistent_Storage_Block::get_sync() const +{ + return this->sync_; +} + +size_t +Persistent_Storage_Block::block_number() const +{ + return this->block_number_; +} + +unsigned char* +Persistent_Storage_Block::data() const +{ + return this->data_; +} + +void +Persistent_Storage_Block::reassign_data(unsigned char* newptr, + bool delete_old) +{ + if (delete_old) + { + delete [] this->data_; + } + this->data_ = newptr; +} + +void +Persistent_Storage_Block::set_callback(Persistent_Callback* callback) +{ + this->callback_ = callback; +} + +Persistent_Callback* +Persistent_Storage_Block::get_callback() const +{ + return this->callback_; +} + +void +Persistent_Storage_Block::set_allocator_owns(bool allocator_owns) +{ + this->allocator_owns_ = allocator_owns; +} + +bool +Persistent_Storage_Block::get_allocator_owns() const +{ + return this->allocator_owns_; +} + +Persistent_File_Allocator::Persistent_File_Allocator() + : pstore_() + , terminate_thread_(false) + , thread_active_(false) + , wake_up_thread_(queue_lock_) +{ +} + +Persistent_File_Allocator::~Persistent_File_Allocator() +{ + this->shutdown_thread(); +} + +bool +Persistent_File_Allocator::open (const char* filename, + const size_t block_size) +{ + bool file_opened = this->pstore_.open(filename, block_size); + if (file_opened) + { + this->thread_active_ = true; + this->thread_manager_.spawn(this->thr_func, this); + } + return file_opened; +} + +void +Persistent_File_Allocator::shutdown() +{ + this->shutdown_thread(); +} + +Persistent_Storage_Block* +Persistent_File_Allocator::allocate() +{ + Persistent_Storage_Block* result = 0; + size_t block_number = 0; + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, 0); + if (!this->allocate_block(block_number)) + { + //@@todo: this should never happen + // why not. What if the disk is full? Oh, I see we + // allocate non-existent blocks. FIX this + } + if (DEBUG_LEVEL > 0) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Persistent_File_Allocator::allocate: %d\n"), + ACE_static_cast (int, block_number) + )); + result = this->allocate_at(block_number); + return result; +} + +Persistent_Storage_Block* +Persistent_File_Allocator::allocate_at(size_t block_number) +{ + Persistent_Storage_Block* result = 0; + this->used(block_number); + if (DEBUG_LEVEL > 0) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Persistent_File_Allocator::allocate at : %d\n"), + ACE_static_cast (int, block_number) + )); + ACE_NEW_RETURN(result, Persistent_Storage_Block( + block_number, + this->block_size()), + 0); + return result; +} + +Persistent_Storage_Block* +Persistent_File_Allocator::allocate_nowrite() +{ + Persistent_Storage_Block* result = 0; + ACE_NEW_RETURN(result, Persistent_Storage_Block(~0, 0), 0); + result->set_no_write(); + return result; +} + +void +Persistent_File_Allocator::used(size_t block_number) +{ + ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->free_blocks_lock_); + if (DEBUG_LEVEL > 0) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Persistent_File_Allocator::used: %d\n"), + ACE_static_cast (int, block_number) + )); + ACE_ASSERT (!this->free_blocks_.is_set (block_number)); + this->free_blocks_.set_bit(block_number, true); +} + +void +Persistent_File_Allocator::free(size_t block_number) +{ + if (DEBUG_LEVEL > 0) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Persistent_File_Allocator::free: %d\n"), + ACE_static_cast (int, block_number) + )); + ACE_ASSERT (this->free_blocks_.is_set (block_number)); + this->free_block(block_number); +} + +size_t +Persistent_File_Allocator::block_size() const +{ + return pstore_.block_size(); +} + +bool +Persistent_File_Allocator::read(Persistent_Storage_Block* psb) +{ + bool result = this->thread_active_; + bool cached = false; + if (result) + { + Persistent_Storage_Block** psbtemp = 0; + { + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->queue_lock_, false); + size_t queue_size = this->block_queue_.size(); + for (size_t idx = 0; !cached && (idx < queue_size); ++idx) + { + // We want to start at the end of the queue and work backwards... + size_t actual_block = (queue_size - idx) - 1; + if (0 == this->block_queue_.get(psbtemp, actual_block)) + { + cached = ((*psbtemp)->block_number() == psb->block_number()); + } + } + // this needs to be done in the guarded section + if (cached && (0 != psbtemp)) + { + ACE_OS::memcpy(psb->data(), (*psbtemp)->data(), this->block_size()); + } + } + if (!cached) + { + result = pstore_.read(psb->block_number(), psb->data()); + } + } + return result; +} + +bool +Persistent_File_Allocator::write(Persistent_Storage_Block* psb) +{ + bool result = this->thread_active_; + if (result) + { + Persistent_Storage_Block* ourpsb = psb; + if (!psb->get_allocator_owns()) + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Copy PSB %d\n") + , ACE_static_cast (int, psb->block_number ()) + )); + ACE_NEW_RETURN(ourpsb, Persistent_Storage_Block(*psb), false); + ourpsb->set_allocator_owns(true); + } + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->queue_lock_, false); + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Queueing PSB to write block %d\n") + , ACE_static_cast (int, psb->block_number ()) + )); + result = (0 == this->block_queue_.enqueue_tail(ourpsb)); + this->wake_up_thread_.signal(); + } + return result; +} + +void +Persistent_File_Allocator::free_block(const size_t block_number) +{ + ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->free_blocks_lock_); + ACE_ASSERT (this->free_blocks_.is_set (block_number)); + this->free_blocks_.set_bit(block_number, false); +} + +bool +Persistent_File_Allocator::allocate_block(size_t& block_number) +{ + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->free_blocks_lock_, 0); + block_number = this->free_blocks_.find_first_bit(false); + return true; +} + +ACE_THR_FUNC_RETURN +Persistent_File_Allocator::thr_func(void * arg) +{ + Persistent_File_Allocator* pfa = ACE_static_cast (Persistent_File_Allocator*, + arg); + pfa->run(); + return 0; +} + +size_t +Persistent_File_Allocator::file_size () const +{ + return this->pstore_.size (); +} + +void +Persistent_File_Allocator::shutdown_thread() +{ + if (this->thread_active_) + { + ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->queue_lock_); + this->terminate_thread_ = true; + this->wake_up_thread_.signal(); + ace_mon.release(); + this->thread_manager_.close(); + ACE_ASSERT (!this->terminate_thread_); + ACE_ASSERT (!this->thread_active_); + } +} + +void +Persistent_File_Allocator::run() +{ + // We need this because we could be working on writing data + // when a call to terminate comes in! + bool do_more_work = true; + while (do_more_work) + { + do_more_work = false; + Persistent_Storage_Block * blk = 0; + { + ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->queue_lock_); + while (this->block_queue_.is_empty() && !terminate_thread_) + { + this->wake_up_thread_.wait(); + } + // Awkward interface to peek at head of unbounded queue + Persistent_Storage_Block ** pblk = 0; + if (0 == this->block_queue_.get(pblk)) + { + do_more_work = true; + blk = *pblk; + } + } + if (0 != blk) + { + Persistent_Callback *callback = blk->get_callback(); + if (!blk->get_no_write()) + { + pstore_.write(blk->block_number(), blk->data(), blk->get_sync()); + } + { + Persistent_Storage_Block * blk2 = 0; + ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->queue_lock_); + this->block_queue_.dequeue_head (blk2); + // if this triggers, someone pushed onto the head of the queue + // or removed the head from the queue without telling ME. + ACE_ASSERT (blk2 == blk); + } + // If we own the block, then delete it. + if (blk->get_allocator_owns()) + { + delete blk; + blk = 0; + } + if (0 != callback) + { + callback->persist_complete(); + } + } + } + this->terminate_thread_ = false; + this->thread_active_ = false; +} + +} /* namespace TAO_NOTIFY */ + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +template class ACE_Node<size_t>; +template class ACE_Unbounded_Stack<size_t>; +template class ACE_Node<TAO_NOTIFY::Persistent_Storage_Block*>; +template class ACE_Unbounded_Queue<TAO_NOTIFY::Persistent_Storage_Block*>; +template class ACE_Unbounded_Queue_Iterator<TAO_NOTIFY::Persistent_Storage_Block*>; +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#pragma instantiate ACE_Node<size_t> +#pragma instantiate ACE_Unbounded_Stack<size_t> +#pragma instantiate ACE_Node<TAO_NOTIFY::Persistent_Storage_Block*> +#pragma instantiate ACE_Unbounded_Queue<TAO_NOTIFY::Persistent_Storage_Block*> +#pragma instantiate ACE_Unbounded_Queue_Iterator<TAO_NOTIFY::Persistent_Storage_Block*> +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.h b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.h new file mode 100644 index 00000000000..28c461643ed --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Persistent_File_Allocator.h @@ -0,0 +1,203 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Persistent_File_Allocator.h + * + * $Id$ + * + * A Persistent_File_Allocator manages a free list and allocates and + * deallocates blocks from a Persistent_File. There should be only one + * Persistent_File_Allocator for each Persistent_File. + * + * @author Jonathan Pollack <pollack_j@ociweb.com> + */ +//============================================================================= + +#ifndef PERSISTENT_FILE_ALLOCATOR_H +#define PERSISTENT_FILE_ALLOCATOR_H +#include /**/ "ace/pre.h" +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "notify_export.h" +#include "Persistent_File.h" +#include "Bit_Vector.h" +#include "ace/Containers_T.h" +#include "ace/Unbounded_Queue.h" +#include "ace/Thread_Manager.h" + +namespace TAO_NOTIFY +{ + + +/// \brief An interface to allow callbacks on completion of persistent storage +/// requests. +class TAO_Notify_Export Persistent_Callback +{ +public: + /// \brief Called by a Persistent_File_Allocator when a write request has + /// completed. + virtual void persist_complete() = 0; +}; + +/** + * \brief A class to represent a block on disk. + * + * Contains the raw data to be written on disk as well as + * positioning information, synchronization information, and a pointer + * to a callback. + */ +class TAO_Notify_Export Persistent_Storage_Block +{ +public: + /// The constructor. Initializes the callback to NULL. + Persistent_Storage_Block( + const size_t block_number, + const size_t block_size); + /// The copy constructor. Makes a deep copy of the passed in PSB. + Persistent_Storage_Block(const Persistent_Storage_Block& psb); + /// The destructor. + ~Persistent_Storage_Block(); + + /// Set our block to not have any data at all - a no-op. This can be + /// used to implement a checkpoint in the write stream. + void set_no_write(); + /// Find out whether we have data to be written. + bool get_no_write(); + + /// Set our block to be written as a near-atomic operation. + void set_sync(); + /// Find out whether this block should be written near-atomically. + bool get_sync() const; + + /// Find out our physical block number. + size_t block_number() const; + + /// Return our data to the user. + unsigned char* data() const; + /// Set our data pointer, and optionally delete it. + void reassign_data(unsigned char* newptr, bool delete_old = false); + + /// Return block number and relinquish ownership. + size_t detach (); + + /// Set our callback. + void set_callback(Persistent_Callback* callback); + /// Get our callback. + Persistent_Callback* get_callback() const; + + /// Set ownership of this PSB. + void set_allocator_owns(bool allocator_owns = true); + /// Get ownership status of this PSB. + bool get_allocator_owns() const; + +private: + /// Our raw data. + unsigned char* data_; + /// The block number corresponding to our data. + size_t block_number_; + /// Are we a no-op with just a callback? + bool no_write_; + /// Write in near-atomic fashion. + bool sync_; + /// The size of our block. + size_t block_size_; + /// Our optional callback function, to be used in such things as state + /// transitions. + Persistent_Callback* callback_; + /// Does the allocator obtain ownership of our block? + bool allocator_owns_; +}; + +/** + * \brief A class that manages the details of persistent storage. + * + * Maintains a free list, write queue, allocations of new + * blocks, reads, and writes. This class also manages a thread that performs + * background updating of a Persistent_File. + * @@todo this is too much for one class to do. It should be refactored. + */ +class TAO_Notify_Export Persistent_File_Allocator +{ +public: + /// The constructor. + Persistent_File_Allocator(); + /// The destructor. + ~Persistent_File_Allocator(); + + bool open (const char* filename, + const size_t block_size = 512); + + /// \brief Wait for pending I/O and terminate our work thread. + void shutdown(); + + /// Allocate a new Persistent_Storage_Block and initialize it to an unused + /// block of storage. + Persistent_Storage_Block* allocate(); + + /// \brief Allocate a new Persistent_Storage_Block at a given address + Persistent_Storage_Block* allocate_at(size_t block_number); + + /// \brief Allocate a PSB that is marked to not persist + Persistent_Storage_Block* allocate_nowrite(); + + /// \brief Mark a block as used, removing it from the free list. + void used(size_t block_number); + + /// \brief Mark a block number as able to be used again. + void free(size_t block_number); + + /// \brief Access block size. + size_t block_size() const; + + /// \brief Read data into a PSB. + /// + /// Data will come either from the queue of blocks to be written, or + /// it will be read from the file if there are no queued write requests for + /// this block. + bool read(Persistent_Storage_Block* psb); + + /// \brief Write this block to the file, + /// + /// Add the Persistent_Storage_Block to our write queue and let the + /// worker thread handle writing this to the Persistent_File. + bool write(Persistent_Storage_Block* psb); + + /// for information (unit test) only. + size_t file_size () const; + +private: + /// Free a previously assigned block. + void free_block(const size_t block_number); + /// Find and allocate a free block. + bool allocate_block(size_t& block_number); + + /// Used during thread startup to cast us back to ourselves and call the + /// run() method. + static ACE_THR_FUNC_RETURN thr_func(void * arg); + /// Wait for pending I/O to complete and shut our worker thread down safely. + void shutdown_thread(); + /// The worker's execution thread. + void run(); + +private: + ACE_Thread_Manager thread_manager_; + Persistent_File pstore_; + Bit_Vector free_blocks_; + ACE_Unbounded_Queue<Persistent_Storage_Block*> block_queue_; + ACE_SYNCH_MUTEX lock_; + ACE_SYNCH_MUTEX free_blocks_lock_; + ACE_SYNCH_MUTEX queue_lock_; + bool terminate_thread_; + bool thread_active_; + ACE_SYNCH_CONDITION wake_up_thread_; +}; + +} /* namespace TAO_NOTIFY */ + +#include /**/ "ace/post.h" +#endif /* PERSISTENT_FILE_ALLOCATOR_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Properties.h b/TAO/orbsvcs/orbsvcs/Notify/Properties.h index 4542a14bff6..7801ed6dc99 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Properties.h +++ b/TAO/orbsvcs/orbsvcs/Notify/Properties.h @@ -62,6 +62,9 @@ public: CORBA::Boolean asynch_updates (void); void asynch_updates (CORBA::Boolean asynch_updates); + bool allow_reconnect (void); + void allow_reconnect (bool b); + // Turn on/off update messages. CORBA::Boolean updates (void); void updates (CORBA::Boolean updates); @@ -112,6 +115,9 @@ protected: /// True if send asynch updates. CORBA::Boolean asynch_updates_; + /// True if clients can reconnect to proxies. + bool allow_reconnect_; + /// True if updates are enabled (default). CORBA::Boolean updates_; diff --git a/TAO/orbsvcs/orbsvcs/Notify/Properties.inl b/TAO/orbsvcs/orbsvcs/Notify/Properties.inl index 2b83846458c..c8a7893f4d7 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Properties.inl +++ b/TAO/orbsvcs/orbsvcs/Notify/Properties.inl @@ -60,6 +60,18 @@ TAO_Notify_Properties::asynch_updates (CORBA::Boolean asynch_updates) this->asynch_updates_ = asynch_updates; } +ACE_INLINE bool +TAO_Notify_Properties::allow_reconnect (void) +{ + return this->allow_reconnect_; +} + +ACE_INLINE void +TAO_Notify_Properties::allow_reconnect (bool b) +{ + this->allow_reconnect_ = b; +} + ACE_INLINE CORBA::Boolean TAO_Notify_Properties::updates (void) { diff --git a/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.cpp b/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.cpp index 77a4fbc7364..bb5a906dc07 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.cpp @@ -34,9 +34,9 @@ TAO_Notify_PropertySeq::init (const CosNotification::PropertySeq& prop_seq) } int -TAO_Notify_PropertySeq::populate (CosNotification::PropertySeq_var& prop_seq) +TAO_Notify_PropertySeq::populate (CosNotification::PropertySeq_var& prop_seq) const { - PROPERTY_MAP::ITERATOR iterator (this->property_map_); + PROPERTY_MAP::CONST_ITERATOR iterator (this->property_map_); int index = prop_seq->length (); prop_seq->length (ACE_static_cast (CORBA::ULong, @@ -52,3 +52,11 @@ TAO_Notify_PropertySeq::populate (CosNotification::PropertySeq_var& prop_seq) return 0; } + +void +TAO_Notify_PropertySeq::add(const ACE_CString& name, const CORBA::Any& val) +{ + int ret = this->property_map_.rebind (name, val); + ACE_ASSERT(ret >= 0); + ACE_UNUSED_ARG (ret); // because the assert disappears in release builds +} diff --git a/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.h b/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.h index ca241e7bbee..1325b724e81 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.h +++ b/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.h @@ -48,7 +48,15 @@ public: int find (const char* name, CosNotification::PropertyValue& value) const; /// Return -1 on error. - int populate (CosNotification::PropertySeq_var& prop_seq); + int populate (CosNotification::PropertySeq_var& prop_seq) const; + + /// return the number of properties available as a sequence + size_t size() const; + +protected: + /// Add the value. Used by subclasses to initialize the property map from their + /// member variables. + void add(const ACE_CString& name, const CORBA::Any& val); protected: /// Property Map. diff --git a/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.inl b/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.inl index 0998ec76b1b..b96345cb11a 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.inl +++ b/TAO/orbsvcs/orbsvcs/Notify/PropertySeq.inl @@ -6,3 +6,11 @@ TAO_Notify_PropertySeq::find (const char* name, CosNotification::PropertyValue& ACE_CString str_name (name); return this->property_map_.find (str_name, value); } + +ACE_INLINE +size_t +TAO_Notify_PropertySeq::size() const +{ + return this->property_map_.current_size(); +} + diff --git a/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.h b/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.h index a0eeef05462..e2d8487d0d8 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.h +++ b/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.h @@ -57,6 +57,9 @@ public: void get (CosNotification::PropertySeq& prop_seq); + /// Return the name + const char * name (void) const; + /// Return the value. CORBA::Boolean value (void) const; diff --git a/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.inl b/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.inl index f5522993d11..b1a469809bb 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.inl +++ b/TAO/orbsvcs/orbsvcs/Notify/Property_Boolean.inl @@ -37,6 +37,13 @@ TAO_Notify_Property_Boolean::operator!= (const CORBA::Boolean &rhs) const return (this->value_ != rhs); } +ACE_INLINE +const char * +TAO_Notify_Property_Boolean::name (void) const +{ + return this->name_; +} + ACE_INLINE CORBA::Boolean TAO_Notify_Property_Boolean::value (void) const { diff --git a/TAO/orbsvcs/orbsvcs/Notify/Property_T.h b/TAO/orbsvcs/orbsvcs/Notify/Property_T.h index ff39b43a068..b1b6b7c39f0 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Property_T.h +++ b/TAO/orbsvcs/orbsvcs/Notify/Property_T.h @@ -57,9 +57,15 @@ public: /// Populate the Property Sequence with this valid value. void get (CosNotification::PropertySeq& prop_seq); + // assign a new value + void assign (const TYPE& value); + /// Return the value. const TYPE& value (void) const; + /// Return the name + const char * name (void) const; + /// Is the current value valid CORBA::Boolean is_valid (void) const; @@ -125,6 +131,9 @@ public: /// Returns 0 on success, -1 on error int set (const TAO_Notify_PropertySeq& property_seq); + /// Return the name + const char * name (void) const; + /// Return the value. const TYPE& value (void) const; diff --git a/TAO/orbsvcs/orbsvcs/Notify/Property_T.inl b/TAO/orbsvcs/orbsvcs/Notify/Property_T.inl index f014ab89b29..31d5290c72d 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Property_T.inl +++ b/TAO/orbsvcs/orbsvcs/Notify/Property_T.inl @@ -8,6 +8,13 @@ TAO_Notify_PropertyBase_T<TYPE>::value (void) const return this->value_; } +template <class TYPE> ACE_INLINE +const char * +TAO_Notify_PropertyBase_T<TYPE>::name (void) const +{ + return this->name_; +} + template <class TYPE> ACE_INLINE CORBA::Boolean TAO_Notify_PropertyBase_T<TYPE>::is_valid (void) const { @@ -32,14 +39,33 @@ TAO_Notify_PropertyBase_T<TYPE>:: invalidate (void) this->valid_ = 0; } +template <class TYPE> ACE_INLINE +void +TAO_Notify_PropertyBase_T<TYPE>:: assign (const TYPE& value) +{ + this->value_ = value; + this->valid_ = 1; +} + + + /******************************************************************************/ +template <class TYPE> ACE_INLINE +const char * +TAO_Notify_StructProperty_T<TYPE>::name (void) const +{ + return this->name_; +} + template <class TYPE> ACE_INLINE const TYPE& TAO_Notify_StructProperty_T<TYPE>::value (void) const { return this->value_; } + + template <class TYPE> ACE_INLINE CORBA::Boolean TAO_Notify_StructProperty_T<TYPE>::is_valid (void) const { diff --git a/TAO/orbsvcs/orbsvcs/Notify/Proxy.cpp b/TAO/orbsvcs/orbsvcs/Notify/Proxy.cpp index 34e95f70911..ab109a6a674 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Proxy.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/Proxy.cpp @@ -14,6 +14,7 @@ ACE_RCSID(RT_Notify, TAO_Notify_Proxy, "$Id$") #include "Worker_Task.h" #include "Properties.h" #include "POA_Helper.h" +#include "Topology_Saver.h" TAO_Notify_Proxy::TAO_Notify_Proxy (void) :updates_off_ (0) @@ -29,8 +30,17 @@ TAO_Notify_Proxy::activate (PortableServer::Servant servant ACE_ENV_ARG_DECL) { // Set the POA that we use to return our <ref> this->poa_ = this->proxy_poa_; + return TAO_Notify_Object::activate (servant ACE_ENV_ARG_PARAMETER); +} - return this->proxy_poa_->activate (servant, this->id_ ACE_ENV_ARG_PARAMETER); +CORBA::Object_ptr +TAO_Notify_Proxy::activate (PortableServer::Servant servant, + const CosNotifyChannelAdmin::ProxyID proxy_id + ACE_ENV_ARG_DECL) +{ + // Set the POA that we use to return our <ref> + this->poa_ = this->proxy_poa_; + return TAO_Notify_Object::activate (servant, proxy_id ACE_ENV_ARG_PARAMETER); } void @@ -113,3 +123,72 @@ TAO_Notify_Proxy::qos_changed (const TAO_Notify_QoSProperties& qos_properties) if (peer != 0) peer->qos_changed (qos_properties); } + +void +TAO_Notify_Proxy::save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL) +{ + bool changed = this->children_changed_; + this->children_changed_ = false; + this->self_changed_ = false; + + if (is_persistent ()) + { + TAO_NOTIFY::NVPList attrs; + this->save_attrs(attrs); + + const char * type_name = this->get_proxy_type_name (); + bool want_all_children = saver.begin_object(this->id(), type_name, attrs, changed ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + if (want_all_children || this->filter_admin_.is_changed ()) + { + this->filter_admin_.save_persistent(saver ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + + if (want_all_children || this->subscribed_types_.is_changed ()) + { + this->subscribed_types_.save_persistent(saver ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + + // todo: handle removed children + + saver.end_object(this->id(), type_name ACE_ENV_ARG_PARAMETER); + } +} + +void +TAO_Notify_Proxy::save_attrs (TAO_NOTIFY::NVPList& attrs) +{ + TAO_Notify_Object::save_attrs(attrs); + TAO_Notify_Peer * peer = this->peer(); + if (peer != 0) + { + ACE_CString ior; + if (peer->get_ior(ior)) + { + attrs.push_back (TAO_NOTIFY::NVP("PeerIOR", ior)); + } + } +} + +TAO_NOTIFY::Topology_Object* +TAO_Notify_Proxy::load_child (const ACE_CString &type, CORBA::Long id, + const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL) +{ + TAO_NOTIFY::Topology_Object* result = this; + if (type == "subscriptions") + { + // since we initialized our subscribed types to everything + // in the constructor. we have to clear it out first. + this->subscribed_types_.reset(); + result = &this->subscribed_types_; + ACE_CHECK_RETURN(0); + } + else if (type == "filter_admin") + { + result = & this->filter_admin_; + } + return result; +} diff --git a/TAO/orbsvcs/orbsvcs/Notify/Proxy.h b/TAO/orbsvcs/orbsvcs/Notify/Proxy.h index 59a4c347909..69015ddb0c2 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Proxy.h +++ b/TAO/orbsvcs/orbsvcs/Notify/Proxy.h @@ -20,7 +20,7 @@ # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ -#include "Object.h" +#include "Topology_Object.h" #include "EventTypeSeq.h" #include "FilterAdmin.h" #include "Admin.h" @@ -35,7 +35,8 @@ class TAO_Notify_Peer; * @brief Base class proxy for all proxys in NS. * */ -class TAO_Notify_Serv_Export TAO_Notify_Proxy : public virtual TAO_Notify_Object +class TAO_Notify_Serv_Export TAO_Notify_Proxy + : public TAO_NOTIFY::Topology_Parent { friend class TAO_Notify_Peer; @@ -50,35 +51,41 @@ public: ~TAO_Notify_Proxy (); /// Activate - virtual CORBA::Object_ptr activate (PortableServer::Servant servant + virtual CORBA::Object_ptr activate (PortableServer::Servant servant ACE_ENV_ARG_DECL); + /// Activate with a given ID + virtual CORBA::Object_ptr activate ( + PortableServer::Servant servant, + CORBA::Long id + ACE_ENV_ARG_DECL); + /// Deactivate void deactivate (ACE_ENV_SINGLE_ARG_DECL); /// Obtain the Proxy's subscribed types. - void subscribed_types (TAO_Notify_EventTypeSeq& subscribed_types + void subscribed_types (TAO_Notify_EventTypeSeq& subscribed_types ACE_ENV_ARG_DECL); /// Check if this event passes the admin and proxy filters. CORBA::Boolean check_filters ( - const TAO_Notify_Event* event, - TAO_Notify_FilterAdmin& parent_filter_admin, + const TAO_Notify_Event* event, + TAO_Notify_FilterAdmin& parent_filter_admin, CosNotifyChannelAdmin::InterFilterGroupOperator filter_operator ACE_ENV_ARG_DECL ); /// Check if this event passes the admin and proxy filters. CORBA::Boolean check_filters ( - const TAO_Notify_Event_var &event, - TAO_Notify_FilterAdmin& parent_filter_admin, + const TAO_Notify_Event_var &event, + TAO_Notify_FilterAdmin& parent_filter_admin, CosNotifyChannelAdmin::InterFilterGroupOperator filter_operator ACE_ENV_ARG_DECL ); /// Inform this proxy that the following types are being advertised. - void types_changed (const TAO_Notify_EventTypeSeq& added, - const TAO_Notify_EventTypeSeq& removed + void types_changed (const TAO_Notify_EventTypeSeq& added, + const TAO_Notify_EventTypeSeq& removed ACE_ENV_ARG_DECL); /// Have updates been turned off. @@ -92,8 +99,8 @@ public: /// Implement the Obtain Types. virtual CosNotification::EventTypeSeq* obtain_types ( - CosNotifyChannelAdmin::ObtainInfoMode mode, - const TAO_Notify_EventTypeSeq& types + CosNotifyChannelAdmin::ObtainInfoMode mode, + const TAO_Notify_EventTypeSeq& types ACE_ENV_ARG_DECL ) ACE_THROW_SPEC ((CORBA::SystemException)); @@ -107,6 +114,15 @@ public: /// Override, TAO_Notify_Object::qos_changed virtual void qos_changed (const TAO_Notify_QoSProperties& qos_properties); + // TAO_NOTIFY::Topology_Object + + virtual void save_persistent (TAO_NOTIFY::Topology_Saver& saver ACE_ENV_ARG_DECL); + virtual void save_attrs(TAO_NOTIFY::NVPList& attrs); + virtual const char * get_proxy_type_name (void) const = 0; + + virtual TAO_NOTIFY::Topology_Object* load_child (const ACE_CString &type, CORBA::Long id, + const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL); + protected: /// Filter Administration diff --git a/TAO/orbsvcs/orbsvcs/Notify/ProxyConsumer.cpp b/TAO/orbsvcs/orbsvcs/Notify/ProxyConsumer.cpp index 1675a777de5..51bcae25d25 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/ProxyConsumer.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/ProxyConsumer.cpp @@ -40,7 +40,7 @@ TAO_Notify_ProxyConsumer::peer (void) void TAO_Notify_ProxyConsumer::init (TAO_Notify_SupplierAdmin* supplier_admin ACE_ENV_ARG_DECL) { - TAO_Notify_Object::init (supplier_admin); + TAO_NOTIFY::Topology_Object::init (supplier_admin); this->supplier_admin_ = supplier_admin; @@ -70,17 +70,30 @@ TAO_Notify_ProxyConsumer::connect (TAO_Notify_Supplier *supplier ACE_ENV_ARG_DEC ACE_GUARD_THROW_EX (TAO_SYNCH_MUTEX, ace_mon, this->lock_, CORBA::INTERNAL ()); ACE_CHECK; + TAO_Notify_Supplier* deleted_supplier = 0; if (this->is_connected ()) { - supplier->release (); - ACE_THROW (CosEventChannelAdmin::AlreadyConnected ()); + if (TAO_Notify_PROPERTIES::instance()->allow_reconnect()) + { + deleted_supplier = this->supplier_; + } + else + { + supplier->release (); + ACE_THROW (CosEventChannelAdmin::AlreadyConnected ()); + } } - supplier_ = supplier; + this->supplier_ = supplier; this->supplier_admin_->subscribed_types (this->subscribed_types_ ACE_ENV_ARG_PARAMETER); // get the parents subscribed types. ACE_CHECK; + + if (deleted_supplier != 0) + { + deleted_supplier->_decr_refcnt(); + } } // Inform QoS values. diff --git a/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.cpp b/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.cpp index 3034ae07829..1b4049662c1 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.cpp @@ -31,7 +31,7 @@ TAO_Notify_ProxySupplier::~TAO_Notify_ProxySupplier () void TAO_Notify_ProxySupplier::init (TAO_Notify_ConsumerAdmin* consumer_admin ACE_ENV_ARG_DECL) { - TAO_Notify_Object::init (consumer_admin); + TAO_NOTIFY::Topology_Object::init (consumer_admin); this->consumer_admin_ = consumer_admin; @@ -68,16 +68,28 @@ TAO_Notify_ProxySupplier::connect (TAO_Notify_Consumer *consumer ACE_ENV_ARG_DEC CORBA::INTERNAL ()); ACE_CHECK; + TAO_Notify_Consumer * deleted_consumer = 0; if (this->is_connected ()) { - consumer->release (); - ACE_THROW (CosEventChannelAdmin::AlreadyConnected ()); + if (TAO_Notify_PROPERTIES::instance()->allow_reconnect()) + { + deleted_consumer = this->consumer_; + } + else + { + consumer->release (); + ACE_THROW (CosEventChannelAdmin::AlreadyConnected ()); + } } consumer_ = consumer; this->consumer_admin_->subscribed_types (this->subscribed_types_ ACE_ENV_ARG_PARAMETER); // get the parents subscribed types. ACE_CHECK; + if (deleted_consumer != 0) + { + deleted_consumer->_decr_refcnt(); + } } // Inform QoS values. diff --git a/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.h b/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.h index 272c9c3f1ea..903c476b5b1 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.h +++ b/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier.h @@ -89,6 +89,7 @@ public: /// The CA parent. TAO_Notify_ConsumerAdmin* consumer_admin (void); +// const char * get_proxy_type_name (void) const; protected: ///= Data Members. diff --git a/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier_T.cpp b/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier_T.cpp index 86f2c82569b..33c3ed70b8c 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier_T.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/ProxySupplier_T.cpp @@ -140,6 +140,9 @@ TAO_Notify_ProxySupplier_T<SERVANT_TYPE>::suspend_connection (ACE_ENV_SINGLE_ARG } this->consumer_->suspend (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; } template <class SERVANT_TYPE> void diff --git a/TAO/orbsvcs/orbsvcs/Notify/Proxy_T.cpp b/TAO/orbsvcs/orbsvcs/Notify/Proxy_T.cpp index d767751adc3..79856ed053b 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Proxy_T.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/Proxy_T.cpp @@ -99,7 +99,12 @@ TAO_Notify_Proxy_T<SERVANT_TYPE>::add_filter (CosNotifyFilter::Filter_ptr new_fi CORBA::INTERNAL ()); ACE_CHECK_RETURN (0); - return this->filter_admin_.add_filter (new_filter ACE_ENV_ARG_PARAMETER); + CosNotifyFilter::FilterID fid = + this->filter_admin_.add_filter (new_filter ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN(fid); + return fid; } template <class SERVANT_TYPE> void diff --git a/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.cpp b/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.cpp index 805ae87ff67..7af2da443ab 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.cpp @@ -10,18 +10,21 @@ ACE_RCSID(Notify, TAO_Notify_QoSProperties, "$Id$") #include "Property.h" + + TAO_Notify_QoSProperties::TAO_Notify_QoSProperties (void) - : priority_ (CosNotification::Priority) + : event_reliability_(CosNotification::EventReliability) + , connection_reliability_(CosNotification::ConnectionReliability) + , priority_ (CosNotification::Priority) , timeout_ (CosNotification::Timeout) , stop_time_supported_ (CosNotification::StopTimeSupported) , maximum_batch_size_ (CosNotification::MaximumBatchSize) + , max_events_per_consumer_ (CosNotification::MaxEventsPerConsumer) , pacing_interval_ (CosNotification::PacingInterval) , thread_pool_ (NotifyExt::ThreadPool) , thread_pool_lane_ (NotifyExt::ThreadPoolLanes) { - unsupported_[0] = CosNotification::EventReliability; - unsupported_[1] = CosNotification::ConnectionReliability; - unsupported_[2] = CosNotification::StartTimeSupported; + unsupported_[0] = CosNotification::StartTimeSupported; } TAO_Notify_QoSProperties::~TAO_Notify_QoSProperties () @@ -39,6 +42,70 @@ TAO_Notify_QoSProperties::unsupported (ACE_CString& name) return 0; } +void +TAO_Notify_QoSProperties::init () +{ + if (this->event_reliability_.is_valid()) + { + CORBA::Any a; + a <<= this->event_reliability_.value(); + this->add(this->event_reliability_.name(), a); + } + if (this->connection_reliability_.is_valid()) + { + CORBA::Any a; + a <<= this->connection_reliability_.value(); + this->add(this->connection_reliability_.name(), a); + } + if (this->priority_.is_valid()) + { + CORBA::Any a; + a <<= this->priority_.value(); + this->add(this->priority_.name(), a); + } + if (this->timeout_.is_valid()) + { + CORBA::Any a; + a <<= this->timeout_.value(); + this->add(this->timeout_.name(), a); + } + if (this->stop_time_supported_.is_valid()) + { + CORBA::Any a; + a <<= CORBA::Any::from_boolean (this->stop_time_supported_.value()); + this->add(this->stop_time_supported_.name(), a); + } + if (this->maximum_batch_size_.is_valid()) + { + CORBA::Any a; + a <<= this->maximum_batch_size_.value(); + this->add(this->maximum_batch_size_.name(), a); + } + if (this->pacing_interval_.is_valid()) + { + CORBA::Any a; + a <<= this->pacing_interval_.value(); + this->add(this->pacing_interval_.name(), a); + } + if (this->max_events_per_consumer_.is_valid()) + { + CORBA::Any a; + a <<= this->max_events_per_consumer_.value(); + this->add(this->max_events_per_consumer_.name(), a); + } + if (this->thread_pool_.is_valid()) + { + CORBA::Any a; + a <<= this->thread_pool_.value(); + this->add(this->thread_pool_.name(), a); + } + if (this->thread_pool_lane_.is_valid()) + { + CORBA::Any a; + a <<= this->thread_pool_lane_.value(); + this->add(this->thread_pool_lane_.name(), a); + } +} int TAO_Notify_QoSProperties::init (const CosNotification::PropertySeq& prop_seq, CosNotification::PropertyErrorSeq& err_seq) @@ -64,8 +131,10 @@ TAO_Notify_QoSProperties::init (const CosNotification::PropertySeq& prop_seq, Co } if (prop_seq.length () > 0) - { + { // Now, init the supported properties + this->event_reliability_.set (*this); + this->connection_reliability_.set (*this); this->priority_.set (*this); this->timeout_.set (*this); this->stop_time_supported_.set (*this); @@ -81,6 +150,8 @@ TAO_Notify_QoSProperties::init (const CosNotification::PropertySeq& prop_seq, Co int TAO_Notify_QoSProperties::copy (TAO_Notify_QoSProperties& qos_properties) { + qos_properties.event_reliability_ = this->event_reliability_; + qos_properties.connection_reliability_ = this->connection_reliability_; qos_properties.priority_ = this->priority_; qos_properties.timeout_ = this->timeout_; qos_properties.stop_time_supported_ = this->stop_time_supported_; diff --git a/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.h b/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.h index ba418a24cca..91572274252 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.h +++ b/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.h @@ -43,6 +43,9 @@ public: /// Return 0 on success, 1 if unsupported properties were detected and -1 on error. int init (const CosNotification::PropertySeq& prop_seq, CosNotification::PropertyErrorSeq& err_seq); + /// This version initializes the base from our members + void init (); + /// Populate <qos_properties> with all properties from this object. Returns -1 on error. int copy (TAO_Notify_QoSProperties& qos_properties); @@ -61,18 +64,42 @@ public: /// Pacing Interval const TAO_Notify_Property_Time& pacing_interval (void) const; + ///= Accessors + + const TAO_Notify_Property_Short& event_reliability (void) const; + const TAO_Notify_Property_Short& connection_reliability (void) const; + const TAO_Notify_Property_Short& priority (void) const; + const TAO_Notify_Property_Time& timeout (void) const; + const TAO_Notify_Property_Boolean& stop_time_supported (void) const; + const TAO_Notify_Property_Long& max_events_per_consumer (void) const; + + // The non-const accessors are used during topology load + TAO_Notify_Property_Short& event_reliability (void); + TAO_Notify_Property_Short& connection_reliability (void); + TAO_Notify_Property_Short& priority (void); + TAO_Notify_Property_Time& timeout (void); + TAO_Notify_Property_Boolean& stop_time_supported (void); + TAO_Notify_Property_Long& maximum_batch_size (void); + TAO_Notify_Property_Time& pacing_interval (void); + TAO_Notify_Property_Long& max_events_per_consumer (void); protected: /// Return 1 if <value> is unsupported. int unsupported (ACE_CString& name); - enum {UNSUPPORTED_PROPERTY_COUNT = 3}; + enum {UNSUPPORTED_PROPERTY_COUNT = 1}; ///= Unsupported Properties. ACE_CString unsupported_[UNSUPPORTED_PROPERTY_COUNT]; ///= Supported properties + /// Event Reliability + TAO_Notify_Property_Short event_reliability_; + + /// Connection Reliability + TAO_Notify_Property_Short connection_reliability_; + /// Priority TAO_Notify_Property_Short priority_; @@ -85,6 +112,9 @@ protected: /// Maximum Batch Size TAO_Notify_Property_Long maximum_batch_size_; + /// Maximum Events (queue length) Per Consumer + TAO_Notify_Property_Long max_events_per_consumer_; + /// Pacing Interval TAO_Notify_Property_Time pacing_interval_; diff --git a/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.inl b/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.inl index 087ab21febe..14aab6a7866 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.inl +++ b/TAO/orbsvcs/orbsvcs/Notify/QoSProperties.inl @@ -1,5 +1,47 @@ // $Id$ +ACE_INLINE +const TAO_Notify_Property_Short& +TAO_Notify_QoSProperties::event_reliability(void) const +{ + return this->event_reliability_; +} + +ACE_INLINE +const TAO_Notify_Property_Short& +TAO_Notify_QoSProperties::connection_reliability(void) const +{ + return this->connection_reliability_; +} + +ACE_INLINE +const TAO_Notify_Property_Short& +TAO_Notify_QoSProperties::priority(void) const +{ + return this->priority_; +} + +ACE_INLINE +const TAO_Notify_Property_Time& +TAO_Notify_QoSProperties::timeout(void) const +{ + return this->timeout_; +} + +ACE_INLINE +const TAO_Notify_Property_Boolean& +TAO_Notify_QoSProperties::stop_time_supported(void) const +{ + return this->stop_time_supported_; +} + +ACE_INLINE +const TAO_Notify_Property_Long& +TAO_Notify_QoSProperties::max_events_per_consumer (void) const +{ + return this->max_events_per_consumer_; +} + ACE_INLINE const TAO_Notify_Property_ThreadPool& TAO_Notify_QoSProperties::thread_pool (void) const { @@ -23,3 +65,58 @@ TAO_Notify_QoSProperties::pacing_interval (void) const { return this->pacing_interval_; } + +ACE_INLINE +TAO_Notify_Property_Short& +TAO_Notify_QoSProperties::event_reliability(void) +{ + return this->event_reliability_; +} + +ACE_INLINE +TAO_Notify_Property_Short& +TAO_Notify_QoSProperties::connection_reliability(void) +{ + return this->connection_reliability_; +} + +ACE_INLINE +TAO_Notify_Property_Short& +TAO_Notify_QoSProperties::priority(void) +{ + return this->priority_; +} + +ACE_INLINE +TAO_Notify_Property_Time& +TAO_Notify_QoSProperties::timeout(void) +{ + return this->timeout_; +} + +ACE_INLINE +TAO_Notify_Property_Boolean& +TAO_Notify_QoSProperties::stop_time_supported(void) +{ + return this->stop_time_supported_; +} + +ACE_INLINE +TAO_Notify_Property_Long& +TAO_Notify_QoSProperties::max_events_per_consumer (void) +{ + return this->max_events_per_consumer_; +} + + +ACE_INLINE TAO_Notify_Property_Long& +TAO_Notify_QoSProperties::maximum_batch_size (void) +{ + return this->maximum_batch_size_; +} + +ACE_INLINE TAO_Notify_Property_Time& +TAO_Notify_QoSProperties::pacing_interval (void) +{ + return this->pacing_interval_; +} diff --git a/TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.cpp b/TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.cpp new file mode 100644 index 00000000000..09c3a50414c --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.cpp @@ -0,0 +1,39 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** +* @file Reconnect_Worker_T.cpp +* +* $Id$ +* +* @author Jonathan Pollack <pollack_j@ociweb.com> +*/ +//============================================================================= + +#ifndef RECONNECT_WORKER_CPP +#define RECONNECT_WORKER_CPP + +#include "Reconnect_Worker_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace TAO_NOTIFY +{ + template<class TOPOOBJ> + Reconnect_Worker<TOPOOBJ>::Reconnect_Worker() + { + } + + template<class TOPOOBJ> + void + Reconnect_Worker<TOPOOBJ>::work (TOPOOBJ* o ACE_ENV_ARG_DECL) + { + ACE_ASSERT(o != 0); + o->reconnect (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + } +} // namespace TAO_NOTIFY + +#endif /* RECONNECT_WORKER_CPP */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.h b/TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.h new file mode 100644 index 00000000000..0a664b61144 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Reconnect_Worker_T.h @@ -0,0 +1,50 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** +* @file Reconnect_Worker_T.h +* +* $Id$ +* +* @author Jonathan Pollack <pollack_j@ociweb.com> +*/ +//============================================================================= + +#ifndef RECONNECT_WORKER_H +#define RECONNECT_WORKER_H +#include /**/ "ace/pre.h" + +#include "orbsvcs/ESF/ESF_Worker.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace TAO_NOTIFY +{ + /** + * \brief Iterate through children reconnecting after reloading persistent information. + */ + template<class TOPOOBJ> + class Reconnect_Worker : public TAO_ESF_Worker<TOPOOBJ> + { + public: + /// Constructor + Reconnect_Worker(); + + // override virtual ESF_Worker method + virtual void work (TOPOOBJ* o ACE_ENV_ARG_DECL); + }; +} // namespace TAO_NOTIFY + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "Reconnect_Worker_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Reconnect_Worker_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* RECONECT_WORKER_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.cpp b/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.cpp new file mode 100644 index 00000000000..047acc906c0 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.cpp @@ -0,0 +1,267 @@ +/* -*- C++ -*- */ +/** + * @file Reconnection_Registry.cpp + * + * $Id$ + * + * @author Dale Wilson <wilson_d@ociweb.com> + * + */ +#include "Reconnection_Registry.h" + +#if ! defined (__ACE_INLINE__) +#include "Reconnection_Registry.inl" +#endif /* __ACE_INLINE__ */ + +#include <tao/debug.h> +#include "Properties.h" +#include "Topology_Saver.h" +#include <ace/Vector_T.h> +namespace TAO_NOTIFY +{ + Reconnection_Registry::Reconnection_Registry (Topology_Parent & parent) + : highest_id_(0) + { + // not the best technique, here. Take advantage of "protected" + Topology_Object::topology_parent_ = &parent; + } + + Reconnection_Registry::~Reconnection_Registry () + { + } + + ////////////////////////// + // During normal operation + + NotifyExt::ReconnectionRegistry::ReconnectionID + Reconnection_Registry::register_callback ( + NotifyExt::ReconnectionCallback_ptr callback + ACE_ENV_ARG_DECL) + { + //@@todo DO WE NEED THREAD SAFENESS? + NotifyExt::ReconnectionRegistry::ReconnectionID next_id = ++highest_id_; + + if (TAO_debug_level > 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Reconnect registry: registering %d\n"), + ACE_static_cast (int, next_id) + )); + } + TAO_Notify_Properties* properties = TAO_Notify_PROPERTIES::instance(); + CORBA::ORB_var orb = properties->orb (); + + CORBA::String_var cior = orb->object_to_string (callback ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + ACE_CString ior(cior.in ()); + if ( 0 != reconnection_registry_.bind (next_id, ior)) + { + //todo throw something; + } + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + + return next_id; + } + + void + Reconnection_Registry::unregister_callback (NotifyExt::ReconnectionRegistry::ReconnectionID id + ACE_ENV_ARG_DECL) + { + if (TAO_debug_level > 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Reconnect registry: unregistering %d\n"), + ACE_static_cast (int, id) + )); + } + if ( 0 != reconnection_registry_.unbind (id)) + { + //@@todo throw something + } + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + } + + CORBA::Boolean + Reconnection_Registry::is_alive (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) + { + return CORBA::Boolean(1); + } + + ////////////////////// + // During topology save + + void + Reconnection_Registry::save_persistent (Topology_Saver& saver ACE_ENV_ARG_DECL) + { + bool change = this->self_changed_; + this->self_changed_ = false; + this->children_changed_ = false; + + NVPList attrs; + //@@todo: bool want_all_children = + saver.begin_object (0, REGISTRY_TYPE, attrs, change ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + Reconnection_Registry_Type::ENTRY *entry; + for (Reconnection_Registry_Type::ITERATOR iter (this->reconnection_registry_); + iter.next (entry); + iter.advance ()) + { + NVPList cattrs; + if (TAO_debug_level > 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Reconnect registry: saving %d\n"), + ACE_static_cast (int, entry->ext_id_) + )); + } + cattrs.push_back(NVP(RECONNECT_ID, entry->ext_id_)); + cattrs.push_back(NVP(RECONNECT_IOR, entry->int_id_)); + saver.begin_object (entry->ext_id_, REGISTRY_CALLBACK_TYPE, cattrs, true ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + saver.end_object (entry->ext_id_, REGISTRY_CALLBACK_TYPE ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } +// todo: +// for all deleted children +// { +// saver.delete_child(child_type, child_id); +// } + saver.end_object (0, REGISTRY_TYPE ACE_ENV_ARG_PARAMETER); + } + + /////////////////////////////////////// + // During reload of persistent topology + + Topology_Object* + Reconnection_Registry::load_child (const ACE_CString & type, + CORBA::Long, + const NVPList& attrs + ACE_ENV_ARG_DECL_NOT_USED) + { + if (type == REGISTRY_CALLBACK_TYPE) + { + NotifyExt::ReconnectionRegistry::ReconnectionID id; + ACE_CString ior; + if (attrs.load (RECONNECT_ID, id) && attrs.load (RECONNECT_IOR, ior)) + { + if (id > highest_id_) + { + highest_id_ = id; + + if (TAO_debug_level > 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Reconnect registry: reloading %d\n"), + ACE_static_cast (int, id) + )); + } + } + if ( 0 != reconnection_registry_.bind (id, ior)) + { + //@@todo - throw something; + } + } + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Reconnect registry: missing attribute\n") + )); + } + } + return this; + } + + void + Reconnection_Registry::send_reconnect (CosNotifyChannelAdmin::EventChannelFactory_ptr dest_factory + ACE_ENV_ARG_DECL_NOT_USED) + { + TAO_Notify_Properties* properties = TAO_Notify_PROPERTIES::instance(); + CORBA::ORB_var orb = properties->orb (); + ACE_Vector <NotifyExt::ReconnectionRegistry::ReconnectionID> bad_ids; + + Reconnection_Registry_Type::ENTRY *entry; + for (Reconnection_Registry_Type::ITERATOR iter (this->reconnection_registry_); + iter.next (entry); + iter.advance ()) + { + ACE_TRY_NEW_ENV + { + if (TAO_debug_level > 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Reconnection Registry: Sending reconnection to client %d\n"), + ACE_static_cast (int, entry->ext_id_) + )); + } + ACE_CString & ior = entry->int_id_; + CORBA::Object_var obj = orb->string_to_object (ior.c_str () ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + NotifyExt::ReconnectionCallback_var callback = + NotifyExt::ReconnectionCallback::_narrow (obj.in ()); + if (!CORBA::is_nil (callback.in ())) + { + callback->reconnect (dest_factory ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + } + else + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Reconnection Registry: Can't resolve reconnection client's IOR %d\n"), + ACE_static_cast (int, entry->ext_id_) + )); + + //throw this entry away but you've got an iterator so be careful + bad_ids.push_back (entry->ext_id_); + } + } + ACE_CATCHANY + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Reconnection Registry: Exception sending reconnection to client -- discarding registry entry\n") + )); + //throw this entry away but you've got an iterator so be careful + bad_ids.push_back (entry->ext_id_); + //@@todo : we might want to check for retryable exceptions, but for now... + } + ACE_ENDTRY; + } + size_t bad_count = bad_ids.size (); + for (size_t nbad = 0; nbad < bad_count; ++nbad) + { + this->reconnection_registry_.unbind (bad_ids[nbad]); + } + } + + void + Reconnection_Registry::release (void) + { + delete this; + //@@ inform factory + } + + +} // namespace TAO_NOTIFY + + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +template class ACE_Hash_Map_Entry<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString>; +template class ACE_Hash_Map_Manager_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString, ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex>; +template class ACE_Hash_Map_Iterator_Base_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex>; +template class ACE_Hash_Map_Iterator_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex>; +template class ACE_Hash_Map_Reverse_Iterator_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex>; +// vector of int's is instantiated elsewhere +//template class ACE_Vector<NotifyExt::ReconnectionRegistry::ReconnectionID>; +//template class ACE_Array_Base<NotifyExt::ReconnectionRegistry::ReconnectionID>; + +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#pragma instantiate ACE_Hash_Map_Entry<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString > +#pragma instantiate ACE_Hash_Map_Manager_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString ,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex> +#pragma instantiate ACE_Hash_Map_Iterator_Base_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString ,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex> +#pragma instantiate ACE_Hash_Map_Iterator_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString ,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex> +#pragma instantiate ACE_Hash_Map_Reverse_Iterator_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, ACE_CString ,ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, ACE_Null_Mutex> +// vector of int's is instantiated elsewhere +//#pragma instantiate ACE_Vector<NotifyExt::ReconnectionRegistry::ReconnectionID> +//#pragma instantiate ACE_Array_Base<NotifyExt::ReconnectionRegistry::ReconnectionID> +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.h b/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.h new file mode 100644 index 00000000000..f077a3c1695 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.h @@ -0,0 +1,100 @@ +/* -*- C++ -*- */ +/** + * @file Reconnection_Registry.h + * + * $Id$ + * + * @author Dale Wilson <wilson_d@ociweb.com> + * + */ + +#ifndef TAO_NOTIFY_RECONNECTION_REGISTRY_H +#define TAO_NOTIFY_RECONNECTION_REGISTRY_H +#include /**/ <ace/pre.h> +#include /**/ <ace/config-all.h> + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "Topology_Object.h" + +#include "orbsvcs/NotifyExtS.h" + +#include "ace/Hash_Map_Manager_T.h" +#include "ace/Null_Mutex.h" + +namespace TAO_NOTIFY +{ + static const char REGISTRY_TYPE[] = "reconnect_registry"; + static const char RECONNECT_ID[] = "ReconnectId"; + static const char RECONNECT_IOR[] = "IOR"; + static const char REGISTRY_CALLBACK_TYPE[] = "reconnect_callback"; + + /** + * @class Reconnection_Registry + * + * @brief Implementation of ReconnectionRegistry + * + */ + class TAO_Notify_Serv_Export Reconnection_Registry + : public Topology_Object + { + /// The registry consists of a map from ReconnectionID to stringified IOR + typedef ACE_Hash_Map_Manager_Ex<NotifyExt::ReconnectionRegistry::ReconnectionID, + ACE_CString, + ACE_Hash<NotifyExt::ReconnectionRegistry::ReconnectionID>, + ACE_Equal_To<NotifyExt::ReconnectionRegistry::ReconnectionID>, + ACE_SYNCH_NULL_MUTEX> Reconnection_Registry_Type; + + public: + + /// Constructor + Reconnection_Registry (Topology_Parent & parent); + + /// Destructor + ~Reconnection_Registry (); + + ////////////////////////// + // During normal operation + + /// add a new callback to the registry + ::NotifyExt::ReconnectionRegistry::ReconnectionID register_callback ( + ::NotifyExt::ReconnectionCallback_ptr callback + ACE_ENV_ARG_DECL); + + /// + void unregister_callback (::NotifyExt::ReconnectionRegistry::ReconnectionID id + ACE_ENV_ARG_DECL); + + CORBA::Boolean is_alive (ACE_ENV_SINGLE_ARG_DECL); + + ////////////////////// + // During topology save + virtual void save_persistent (Topology_Saver& saver ACE_ENV_ARG_DECL); + + /////////////////////////////////////// + // During reload of persistent topology + + virtual Topology_Object* load_child (const ACE_CString & type, + CORBA::Long id, + const NVPList& attrs + ACE_ENV_ARG_DECL); + + void send_reconnect (CosNotifyChannelAdmin::EventChannelFactory_ptr dest_factory + ACE_ENV_ARG_DECL); + + void release (void); + + private: + Reconnection_Registry_Type reconnection_registry_; + ::NotifyExt::ReconnectionRegistry::ReconnectionID highest_id_; + }; +} // namespace TAO_NOTIFY + +#if defined (__ACE_INLINE__) +#include "Reconnection_Registry.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ <ace/post.h> +#endif /* TAO_NOTIFY_RECONNECTION_REGISTRY_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.inl b/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.inl new file mode 100644 index 00000000000..19ec798e989 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Reconnection_Registry.inl @@ -0,0 +1,2 @@ +// $Id$ + diff --git a/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.cpp b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.cpp new file mode 100644 index 00000000000..7e4894e9a38 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.cpp @@ -0,0 +1,878 @@ +// $Id$ + +#include "Routing_Slip.h" + +#if ! defined (__ACE_INLINE__) +#include "Routing_Slip.inl" +#endif /* __ACE_INLINE__ */ + +#include "Delivery_Request.h" +#include "Delivery_Method_Lookup.h" +#include "Delivery_Method_Dispatch.h" +#include "Worker_Task.h" +#include "ProxyConsumer.h" +#include "ProxySupplier.h" +#include "Event_Persistence_Strategy.h" +#include "Routing_Slip_Persistence_Manager.h" +#include "Routing_Slip_Queue.h" +#include "tao/debug.h" +#include "ace/Dynamic_Service.h" + +//#define DEBUG_LEVEL 9 +#define DEBUG_LEVEL TAO_debug_level + +#define QUEUE_ALLOWED 1 + +namespace TAO_NOTIFY +{ +/////////////////////// +// Routing_Slip Statics + +Routing_Slip_Queue Routing_Slip::persistent_queue_(QUEUE_ALLOWED); + +TAO_SYNCH_MUTEX Routing_Slip::sequence_lock_; +int Routing_Slip::routing_slip_sequence_= 0; +size_t Routing_Slip::count_enter_transient_ = 0; +size_t Routing_Slip::count_continue_transient_ = 0; +size_t Routing_Slip::count_enter_reloaded_ = 0; +size_t Routing_Slip::count_enter_new_ = 0; +size_t Routing_Slip::count_continue_new_ = 0; +size_t Routing_Slip::count_enter_complete_while_new_ = 0; +size_t Routing_Slip::count_enter_saving_ = 0; +size_t Routing_Slip::count_enter_saved_ = 0; +size_t Routing_Slip::count_enter_updating_ = 0; +size_t Routing_Slip::count_enter_changed_while_saving_ = 0; +size_t Routing_Slip::count_continue_changed_while_saving_ = 0; +size_t Routing_Slip::count_enter_changed_ = 0; +size_t Routing_Slip::count_continue_changed_ = 0; +size_t Routing_Slip::count_enter_complete_ = 0; +size_t Routing_Slip::count_enter_deleting_ = 0; +size_t Routing_Slip::count_enter_terminal_ = 0; + +Routing_Slip_Ptr +Routing_Slip::create ( + const TAO_Notify_Event_Ptr& event) +{ + Routing_Slip_Ptr result(new Routing_Slip (event)); + result->this_ptr_ = result; // let the pointers touch so they use the same ref count + + // note we don't care about ultra-precise stats, so no guard for these + if (DEBUG_LEVEL > 1 && ((result->sequence_ % 100) == 0)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Routing_Slip_Statistics\n") + ACE_TEXT (" enter_transient \t%d\n") + ACE_TEXT (" continue_transient \t%d\n") + ACE_TEXT (" enter_reloaded \t%d\n") + ACE_TEXT (" enter_new \t%d\n") + ACE_TEXT (" continue_new \t%d\n") + ACE_TEXT (" enter_complete_while_new \t%d\n") + ACE_TEXT (" enter_saving \t%d\n") + ACE_TEXT (" enter_saved \t%d\n") + ACE_TEXT (" enter_updating \t%d\n") + ACE_TEXT (" enter_changed_while_saving \t%d\n") + ACE_TEXT (" continue_changed_while_saving\t%d\n") + ACE_TEXT (" enter_changed \t%d\n") + ACE_TEXT (" continue_changed \t%d\n") + ACE_TEXT (" enter_complete \t%d\n") + ACE_TEXT (" enter_deleting \t%d\n") + ACE_TEXT (" enter_terminal \t%d\n") + , ACE_static_cast (int, count_enter_transient_) + , ACE_static_cast (int, count_continue_transient_) + , ACE_static_cast (int, count_enter_reloaded_) + , ACE_static_cast (int, count_enter_new_) + , ACE_static_cast (int, count_continue_new_) + , ACE_static_cast (int, count_enter_complete_while_new_) + , ACE_static_cast (int, count_enter_saving_) + , ACE_static_cast (int, count_enter_saved_) + , ACE_static_cast (int, count_enter_updating_) + , ACE_static_cast (int, count_enter_changed_while_saving_) + , ACE_static_cast (int, count_continue_changed_while_saving_) + , ACE_static_cast (int, count_enter_changed_) + , ACE_static_cast (int, count_continue_changed_) + , ACE_static_cast (int, count_enter_complete_) + , ACE_static_cast (int, count_enter_deleting_) + , ACE_static_cast (int, count_enter_terminal_) + )); + } + return result; +} + +// static +Routing_Slip_Ptr +Routing_Slip::create ( + TAO_Notify_EventChannelFactory & ecf, + Routing_Slip_Persistence_Manager * rspm) +{ + Routing_Slip_Ptr result; + ACE_Message_Block * event_mb = 0; + ACE_Message_Block * rs_mb = 0; + if (rspm->reload (event_mb, rs_mb)) + { + TAO_InputCDR cdr_event (event_mb); + TAO_Notify_Event_Ptr event (TAO_Notify_Event::unmarshal (cdr_event)); + if (event != 0) + { + result = create (event); + TAO_InputCDR cdr_rs (rs_mb); + if ( result->unmarshal (ecf, cdr_rs)) + { + result->set_rspm (rspm); + } + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Routing_Slip::create: Unmarshalling failed for routing slip.\n") + )); + result.reset (); + } + } + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Routing_Slip::create: Unmarshalling failed for event.\n") + )); + } + } + delete event_mb; + delete rs_mb; + + return result; +} + +void +Routing_Slip::set_rspm (Routing_Slip_Persistence_Manager * rspm) +{ + this->rspm_ = rspm; + if (rspm_ != 0) + { + rspm->set_callback (this); + } +} + +Routing_Slip::Routing_Slip( + const TAO_Notify_Event_Ptr& event) + : is_safe_ (false) + , until_safe_ (internals_) + , this_ptr_ (0) + , event_(event) + , state_ (rssCREATING) + , complete_requests_ (0) + , rspm_ (0) +{ + Routing_Slip_Guard guard (sequence_lock_); + this->sequence_ = ++routing_slip_sequence_; + if (DEBUG_LEVEL > 1) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: constructor\n"), + this->sequence_ + )); +} + +Routing_Slip::~Routing_Slip () +{ + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: destructor\n"), + this->sequence_ + )); +} + +bool +Routing_Slip::create_persistence_manager() +{ + if (this->rspm_ == 0) + { + Event_Persistence_Strategy * strategy = + ACE_Dynamic_Service <TAO_NOTIFY::Event_Persistence_Strategy>::instance ("Event_Persistence"); + if (strategy != 0) + { + Event_Persistence_Factory * factory = strategy->get_factory (); + if (factory != 0) + { + set_rspm (factory->create_routing_slip_persistence_manager(this)); + } + } + } + return this->rspm_ != 0; +} + +const TAO_Notify_Event_Ptr & +Routing_Slip::event () const +{ + return this->event_; +} + +void +Routing_Slip::wait_persist () +{ + Routing_Slip_Guard guard (this->internals_); + while (!this->is_safe_) + { + this->until_safe_.wait (); + } +} + +void +Routing_Slip::route (TAO_Notify_ProxyConsumer* pc, bool reliable_channel) +{ + ACE_ASSERT(pc != 0); + + TAO_Notify_Refcountable_Guard pcgrd(*pc); + + Routing_Slip_Guard guard (this->internals_); + + size_t request_id = delivery_requests_.size (); + + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: add Delivery_Request #%d: lookup, completed %d of %d\n"), + this->sequence_, + ACE_static_cast (int, request_id), + ACE_static_cast (int, this->complete_requests_), + ACE_static_cast (int, this->delivery_requests_.size ()) + )); + + Delivery_Request_Ptr request (new Delivery_Request (this->this_ptr_, request_id)); + this->delivery_requests_.push_back (request); + Delivery_Method_Lookup method (request, pc); + + if (this->state_ == rssCREATING) + { + if (! reliable_channel) + { + enter_state_transient (guard); + } + else if (ACE_Dynamic_Service <TAO_NOTIFY::Event_Persistence_Strategy>::instance ("Event_Persistence") == 0) + { + enter_state_transient (guard); + } + else if (! this->event_->reliable().is_valid()) + { + enter_state_new (guard); + } + else if (this->event_->reliable().value() == CosNotification::Persistent) + { + enter_state_new (guard); + } + else + { + enter_state_transient (guard); + } + } + guard.release (); + pc->worker_task()->exec (method); +} + +void +Routing_Slip::dispatch (TAO_Notify_ProxySupplier* ps, bool filter) +{ + // cannot be the first action + ACE_ASSERT (this->state_ != rssCREATING); + + TAO_Notify_Refcountable_Guard psgrd(*ps); //@@todo : Need to guard anything else? + Routing_Slip_Guard guard (this->internals_); + + size_t request_id = delivery_requests_.size (); + + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: add Delivery_Request #%d: Dispatch %s; completed %d of %d\n"), + this->sequence_, + ACE_static_cast (int, request_id), + filter ? ACE_TEXT ("Filter") : ACE_TEXT ("No Filter"), + ACE_static_cast (int, this->complete_requests_), + ACE_static_cast (int, this->delivery_requests_.size ()) + )); + + Delivery_Request_Ptr request (new Delivery_Request (this->this_ptr_, request_id)); + if (! ps->has_shutdown() ) + { + this->delivery_requests_.push_back (request); + Delivery_Method_Dispatch method (request, ps, filter); + guard.release (); + if (DEBUG_LEVEL > 8) + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) Routing Slip #%d: dispatching Delivery_Request %d to " + "proxy supplier %d\n", + this->sequence_, + ACE_static_cast (int, request_id), + ps->id())); + ps->worker_task()->exec (method); + } + else + { + if (DEBUG_LEVEL > 5) + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) Routing Slip #%d: not dispatching Delivery_Request %d to " + "proxy supplier %d; already shut down\n", + this->sequence_, + ACE_static_cast (int, request_id), + ps->id())); + } +} + +////////// +// signals + +void +Routing_Slip::delivery_request_complete (size_t request_id) +{ + Routing_Slip_Guard guard (this->internals_); + ACE_ASSERT (request_id < this->delivery_requests_.size ()); + // reset the pointer to allow the delivery_request to be deleted. + this->delivery_requests_[request_id].reset (); + this->complete_requests_ += 1; + + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: delivery_request_complete #%d: completed %d of %d\n"), + this->sequence_, + ACE_static_cast (int, request_id), + ACE_static_cast (int, this->complete_requests_), + ACE_static_cast (int, this->delivery_requests_.size ()) + )); + State state = this->state_; + switch (state) + { + case rssTRANSIENT: + { + continue_state_transient (guard); + break; + } + case rssNEW: + { + continue_state_new (guard); + break; + } + case rssSAVING: + { + enter_state_changed_while_saving (guard); + break; + } + case rssUPDATING: + { + enter_state_changed_while_saving (guard); + break; + } + case rssSAVED: + { + enter_state_changed (guard); + break; + } + case rssCHANGED_WHILE_SAVING: + { + continue_state_changed_while_saving (guard); + break; + } + case rssCHANGED: + { + continue_state_changed (guard); + break; + } + default: + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Notification Service Routing Slip: Unexpected delivery_request_complete in state %d\n"), + ACE_static_cast (int, this->state_) + )); + break; + } + } +} + +void +Routing_Slip::at_front_of_persist_queue () +{ + Routing_Slip_Guard guard (this->internals_); + State state = this->state_; + switch (state) + { + case rssNEW: + { + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: NEW Reached front of queue\n"), + this->sequence_ + )); + enter_state_saving (guard); + break; + } + case rssCOMPLETE_WHILE_NEW: + { + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: COMPLETE_WHILE_NEW Reached front of queue\n"), + this->sequence_ + )); + this->persistent_queue_.complete (); + enter_state_terminal (guard); + break; + } + case rssCHANGED: + { + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: CHANGED Reached front of queue\n"), + this->sequence_ + )); + enter_state_updating (guard); + break; + } + case rssCOMPLETE: + { + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: COMPLETE Reached front of queue\n"), + this->sequence_ + )); + enter_state_deleting (guard); + break; + } + default: + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Routing Slip %d: Unexpected at_front_of_persist_queue in state %d\n"), + this->sequence_, + ACE_static_cast (int, this->state_) + )); + break; + } + } +} + +void +Routing_Slip::persist_complete () +{ + // keep this object around til this method returns. + Routing_Slip_Ptr me(this->this_ptr_); + Routing_Slip_Guard guard (this->internals_); + ACE_ASSERT (guard.locked ()); + + // allow the ConsumerProxy to return from the CORBA push call. + if (! is_safe_) + { + is_safe_ = true; + this->until_safe_.signal (); + } + + State state = this->state_; + switch (state) + { + case rssSAVING: + { + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: SAVING persist complete\n"), + this->sequence_ + )); + enter_state_saved(guard); + break; + } + case rssCHANGED_WHILE_SAVING: + { + enter_state_changed (guard); + break; + } + case rssUPDATING: + { + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: UPDATING persist complete\n"), + this->sequence_ + )); + enter_state_saved (guard); + break; + } + case rssDELETING: + { + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: DELETING persist complete\n"), + this->sequence_ + )); + enter_state_terminal (guard); + break; + } + default: + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Notification Service Routing Slip: Unexpected transition in state %d\n"), + ACE_static_cast (int, this->state_) + )); + break; + } + } + this->persistent_queue_.complete (); +} + +////////////////// +// support methods + +bool +Routing_Slip::all_deliveries_complete () const +{ + return this->complete_requests_ == this->delivery_requests_.size (); +} + +void +Routing_Slip::add_to_persist_queue(Routing_Slip_Guard & guard) +{ + guard.release (); + this->persistent_queue_.add (this->this_ptr_); + guard.acquire (); // necessary? +} + +//////////////////// +// State transitions + +void +Routing_Slip::enter_state_new (Routing_Slip_Guard & guard) +{ + ++count_enter_new_; + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state NEW\n"), + this->sequence_ + )); + this->state_ = rssNEW; + add_to_persist_queue(guard); +} + +void +Routing_Slip::continue_state_new (Routing_Slip_Guard & guard) +{ + ++count_continue_new_; + if (all_deliveries_complete ()) + { + this->enter_state_complete_while_new (guard); + } +} +void +Routing_Slip::enter_state_complete_while_new (Routing_Slip_Guard & guard) +{ + ++count_enter_complete_while_new_; + ACE_UNUSED_ARG (guard); + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state COMPLETE_WHILE_NEW\n"), + this->sequence_ + )); + // allow the ConsumerProxy to return from the CORBA push call. + if (! is_safe_) + { + is_safe_ = true; + this->until_safe_.signal (); + } + this->state_ = rssCOMPLETE_WHILE_NEW; +} + +void +Routing_Slip::enter_state_reloaded (Routing_Slip_Guard & guard) +{ + ++count_enter_reloaded_; + ACE_UNUSED_ARG (guard); + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #&d: enter state RELOADED\n"), + this->sequence_ + )); + this->state_ = rssRELOADED; +} + +void +Routing_Slip::enter_state_transient (Routing_Slip_Guard & guard) +{ + ++count_enter_transient_; + ACE_UNUSED_ARG (guard); + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state TRANSIENT\n"), + this->sequence_ + )); + this->state_ = rssTRANSIENT; + if (! is_safe_) + { + is_safe_ = true; + this->until_safe_.signal (); + } + if (all_deliveries_complete ()) + { + enter_state_terminal (guard); + } +} + +void +Routing_Slip::continue_state_transient (Routing_Slip_Guard & guard) +{ + ++count_continue_transient_; + if (all_deliveries_complete ()) + { + enter_state_terminal (guard); + } +} +void +Routing_Slip::enter_state_saving (Routing_Slip_Guard & guard) +{ + ++count_enter_saving_; + if (!create_persistence_manager ()) + { + // Note This should actually be a throw (out of memory) + // but we cheat and make this a transient event. + this->persistent_queue_.complete (); + enter_state_transient (guard); + } + else + { + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state SAVING\n"), + this->sequence_ + )); + this->state_ = rssSAVING; + + TAO_OutputCDR event_cdr; + this->event_->marshal (event_cdr); + + const ACE_Message_Block *event_mb = event_cdr.begin (); + TAO_OutputCDR rs_cdr; + marshal (rs_cdr); + const ACE_Message_Block *rs_mb = rs_cdr.begin (); + + guard.release (); + this->rspm_->store (*event_mb, *rs_mb); + + guard.acquire (); // necessary? + } +} + +void +Routing_Slip::enter_state_saved (Routing_Slip_Guard & guard) +{ + ++count_enter_saved_; + ACE_UNUSED_ARG (guard); + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state SAVED\n"), + this->sequence_ + )); + this->state_ = rssSAVED; +} + +void +Routing_Slip::enter_state_updating (Routing_Slip_Guard & guard) +{ + ++count_enter_updating_; + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state UPDATING\n"), + this->sequence_ + )); + this->state_ = rssUPDATING; + + TAO_OutputCDR rs_cdr; + marshal (rs_cdr); + const ACE_Message_Block *rs_mb = rs_cdr.begin (); + guard.release (); + + ACE_ASSERT (this->rspm_ != 0); + this->rspm_->update (*rs_mb); + guard.acquire (); // necessary? +} + + +void +Routing_Slip::enter_state_changed_while_saving (Routing_Slip_Guard & guard) +{ + ++count_enter_changed_while_saving_; + ACE_UNUSED_ARG (guard); + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state CHANGED_WHILE_SAVING\n"), + this->sequence_ + )); + this->state_ = rssCHANGED_WHILE_SAVING; +} + +void +Routing_Slip::continue_state_changed_while_saving (Routing_Slip_Guard & guard) +{ + ACE_UNUSED_ARG (guard); + // no action necessary +} + +void +Routing_Slip::enter_state_changed (Routing_Slip_Guard & guard) +{ + ++count_enter_changed_; + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state CHANGED\n"), + this->sequence_ + )); + // complete state change BEFORE initiating request to avoid + // race condition if request finishes before state is stable. + this->state_ = rssCHANGED; + if (all_deliveries_complete ()) + { + enter_state_complete (guard); + } + add_to_persist_queue (guard); +} + +void +Routing_Slip::continue_state_changed (Routing_Slip_Guard & guard) +{ + ++count_continue_changed_; + if (all_deliveries_complete ()) + { + enter_state_complete (guard); + } +} + +void +Routing_Slip::enter_state_complete (Routing_Slip_Guard & guard) +{ + ++count_enter_complete_; + ACE_UNUSED_ARG (guard); + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state COMPLETE\n"), + this->sequence_ + )); + this->state_ = rssCOMPLETE; +} + +void +Routing_Slip::enter_state_deleting (Routing_Slip_Guard & guard) +{ + ++count_enter_deleting_; + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state DELETING\n"), + this->sequence_ + )); + this->state_ = rssDELETING; + guard.release (); + this->rspm_->remove (); + guard.acquire (); // necessary? +} + +void +Routing_Slip::enter_state_terminal (Routing_Slip_Guard & guard) +{ + ++count_enter_terminal_; + ACE_UNUSED_ARG (guard); + ACE_ASSERT( this->is_safe_); + if (DEBUG_LEVEL > 8) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Routing Slip #%d: enter state TERMINAL\n"), + this->sequence_ + )); + this->state_ = rssTERMINAL; + this->this_ptr_.reset (); +} + +void +Routing_Slip::marshal (TAO_OutputCDR & cdr) +{ + size_t request_count = this->delivery_requests_.size(); + cdr.write_ulong (request_count - this->complete_requests_); + for (size_t nreq = 0; nreq < request_count; ++nreq) + { + Delivery_Request * request = this->delivery_requests_[nreq].get (); + if (request != 0) + { + request->marshal (cdr); + } + } +} + +bool +Routing_Slip::unmarshal (TAO_Notify_EventChannelFactory &ecf, TAO_InputCDR & cdr) +{ + CORBA::ULong count = 0; + cdr.read_ulong (count); + for (size_t nreq = 0; nreq < count; ++nreq) + { + ACE_CDR::Octet code = 0; + while (cdr.read_octet(code)) + { + ACE_TRY_NEW_ENV + { + if (code == Delivery_Method_Dispatch::persistence_code) + { + Delivery_Request_Ptr request(new Delivery_Request(this_ptr_, this->delivery_requests_.size ())); + Delivery_Method * method = Delivery_Method_Dispatch::create ( + request, + ecf, + cdr + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + if (method != 0) + { + this->delivery_requests_.push_back (request); + this->delivery_methods_.push_back (method); + } + } + else if (code == Delivery_Method_Lookup::persistence_code) + { + Delivery_Request_Ptr request(new Delivery_Request(this_ptr_, this->delivery_requests_.size ())); + Delivery_Method * method = Delivery_Method_Lookup::create ( + request, + ecf, + cdr + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK + if (method != 0) + { + this->delivery_requests_.push_back (request); + this->delivery_methods_.push_back (method); + } + } + } + ACE_CATCHANY; + { + // @@todo should we log this? + // just ignore failures + } + ACE_ENDTRY; + } + } + return this->delivery_requests_.size () > 0; +} + +void +Routing_Slip::reconnect (ACE_ENV_SINGLE_ARG_DECL) +{ + Routing_Slip_Guard guard (this->internals_); + enter_state_saved (guard); + guard.release (); + //@@todo is there a worker_task available to do this? + size_t count = this->delivery_methods_.size (); + for (size_t nmethod = 0; nmethod < count; ++nmethod) + { + this->delivery_methods_[nmethod] ->execute (TAO_Notify_Method_Request::EXECUTE ACE_ENV_ARG_PARAMETER); + } + this->delivery_methods_.clear (); +} + +int +Routing_Slip::sequence() const +{ + return this->sequence_; +} + +bool +Routing_Slip::should_retry () const +{ + // simple minded test: if it's transient, don't retry it + // @@todo Eventually this should check timeout, discard policy, etc. + return this->state_ != rssTRANSIENT; +} + + + +} // namespace + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +template class ACE_Auto_Basic_Ptr<TAO_NOTIFY::Routing_Slip>; +template class ACE_Strong_Bound_Ptr<TAO_NOTIFY::Routing_Slip, TAO_SYNCH_MUTEX>; +template class ACE_Auto_Basic_Ptr<TAO_NOTIFY::Delivery_Request>; +template class ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX>; +template class ACE_Vector <TAO_NOTIFY::Delivery_Request_Ptr>; +template class ACE_Array_Base<ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX> >; +template class ACE_Vector <TAO_NOTIFY::Delivery_Request *>; +template class ACE_Array_Base<TAO_NOTIFY::Delivery_Request *>; +template class ACE_Dynamic_Service <TAO_NOTIFY::Event_Persistence_Strategy>; +template class ACE_Array_Base<TAO_NOTIFY::Delivery_Method*>; +template class ACE_Vector<TAO_NOTIFY::Delivery_Method*>; +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#pragma instantiate ACE_Auto_Basic_Ptr<TAO_NOTIFY::Routing_Slip> +#pragma instantiate ACE_Strong_Bound_Ptr<TAO_NOTIFY::Routing_Slip,TAO_SYNCH_MUTEX> +#pragma instantiate ACE_Auto_Basic_Ptr<TAO_NOTIFY::Delivery_Request> +#pragma instantiate ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX> +#pragma instantiate ACE_Vector <TAO_NOTIFY::Delivery_Request_Ptr> +#pragma instantiate ACE_Array_Base<ACE_Strong_Bound_Ptr<TAO_NOTIFY::Delivery_Request,TAO_SYNCH_MUTEX> > +#pragma instantiate ACE_Vector <TAO_NOTIFY::Delivery_Request *> +#pragma instantiate ACE_Array_Base<TAO_NOTIFY::Delivery_Request *> +#pragma instantiate ACE_Dynamic_Service <TAO_NOTIFY::Event_Persistence_Strategy> +#pragma instantiate ACE_Array_Base<TAO_NOTIFY::Delivery_Method*> +#pragma instantiate ACE_Vector<TAO_NOTIFY::Delivery_Method*> +#endif /*ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.h b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.h new file mode 100644 index 00000000000..477f6117d37 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip.h @@ -0,0 +1,241 @@ +/* -*- C++ -*- */ +/** + * @file Routing_Slip.h + * + * $Id$ + * + * @author Dale Wilson <wilson_d@ociweb.com> + * + * + */ + +#ifndef TAO_NOTIFY_ROUTING_SLIP_H +#define TAO_NOTIFY_ROUTING_SLIP_H +#include "ace/pre.h" + +#include "notify_export.h" +#include "Event.h" +#include "Types.h" +#include "Delivery_Request.h" +#include "Event_Persistence_Factory.h" + +#include "Persistent_File_Allocator.h" // for Persistent_Callback + +#include <ace/Vector_T.h> +#include <ace/Malloc_Base.h> // necessary? + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +// Forward declarations of classes/pointers/collections +// referenced from this header +class TAO_Notify_EventChannelFactory; +class TAO_Notify_Method_Request; + +namespace TAO_NOTIFY +{ + +class TAO_Notify_Export Routing_Slip_Persistence_Manager; + +// Forward declarations of TAO_NOTIFY classes/pointers/collections +// referenced from this header + +/// A vector of Delivery Requests. The body of a Routing_Slip. +typedef ACE_Vector <Delivery_Request_Ptr> Delivery_Request_Vec; + +class Delivery_Method; +/// A vector of Delivery_Methods. Used during recovery. +typedef ACE_Vector <Delivery_Method *> Delivery_Method_Vec; + +class Routing_Slip; +/// A reference-counted smart pointer to a Routing_Slip +typedef ACE_Strong_Bound_Ptr<Routing_Slip, TAO_SYNCH_MUTEX> Routing_Slip_Ptr; + +class Routing_Slip_Persistence_Manager; + +class Routing_Slip_Queue; + +/** + * \brief Class which manages the delivery of events to destination. + * + * Interacts with persistent storage to provide reliable delivery. + */ +class TAO_Notify_Export Routing_Slip : public Persistent_Callback +{ + typedef ACE_Guard< TAO_SYNCH_MUTEX > Routing_Slip_Guard; +public: + /// "Factory" method for normal use. + static Routing_Slip_Ptr create (const TAO_Notify_Event_Ptr& event); + + /// "Factory" method for use during reload from persistent storage. + static Routing_Slip_Ptr create ( + TAO_Notify_EventChannelFactory & ecf, + Routing_Slip_Persistence_Manager * rspm); + + void set_rspm (Routing_Slip_Persistence_Manager * rspm); + + void reconnect (ACE_ENV_SINGLE_ARG_DECL); + + /// destructor (should be private but that inspires compiler wars) + virtual ~Routing_Slip (); + + ////////////////// + // Action requests + + /// Route this event to destinations + /// must be the Action request after + /// the routing slip is created. + void route (TAO_Notify_ProxyConsumer* pc, bool reliable_channel); + + /// \brief Schedule delivery to a consumer via a proxy supplier + /// \param proxy_supplier the proxy supplier that will deliver the event + /// \param filter should consumer-based filtering be applied? + /// \param a task to use for this work. + void dispatch (TAO_Notify_ProxySupplier * proxy_supplier, bool filter); + + ///////////////////////////////////////// + /// \brief Wait until the event/routing_slip has + /// been saved at least once. + void wait_persist (); + + ///////////////////////////////////// + // signals from the rest of the world + + /// \brief A delivery request has been satisfied. + void delivery_request_complete (size_t request_id); + + /// \brief This Routing_Slip reached the front of the persistence queue + void at_front_of_persist_queue (); + + /// \brief The persistent storage has completed the last request. + virtual void persist_complete (); + + ///////////////////////////////////////////////////// + // \brief Access the event associated with this routing slip + const TAO_Notify_Event_Ptr & event () const; + + /// \brief Provide an identifying number for this Routing Slip + /// to use in debug messages. + int sequence() const; + + /// \brief Should delivery of this event be retried if it fails? + bool should_retry () const; + +private: + //////////////////// + // state transitions + void enter_state_transient (Routing_Slip_Guard & guard); + void continue_state_transient (Routing_Slip_Guard & guard); + void enter_state_reloaded (Routing_Slip_Guard & guard); + void enter_state_new (Routing_Slip_Guard & guard); + void continue_state_new (Routing_Slip_Guard & guard); + void enter_state_complete_while_new (Routing_Slip_Guard & guard); + void enter_state_saving (Routing_Slip_Guard & guard); + void enter_state_saved (Routing_Slip_Guard & guard); + void enter_state_updating (Routing_Slip_Guard & guard); + void enter_state_changed_while_saving (Routing_Slip_Guard & guard); + void continue_state_changed_while_saving (Routing_Slip_Guard & guard); + void enter_state_changed (Routing_Slip_Guard & guard); + void continue_state_changed (Routing_Slip_Guard & guard); + void enter_state_complete (Routing_Slip_Guard & guard); + void enter_state_deleting (Routing_Slip_Guard & guard); + void enter_state_terminal (Routing_Slip_Guard & guard); + +private: + bool create_persistence_manager(); + + /// Private constructor for use by create method + Routing_Slip(const TAO_Notify_Event_Ptr& event); + + /// Test to see if all deliveries are complete. + bool all_deliveries_complete () const; + + /// This routing_slip needs to be saved. + void add_to_persist_queue(Routing_Slip_Guard & guard); + + /// Marshal into a CDR + void marshal (TAO_OutputCDR & cdr); + + /// Marshal from CDR + bool unmarshal (TAO_Notify_EventChannelFactory &ecf, TAO_InputCDR & rscdr); + +private: + /// Protection for internal information + TAO_SYNCH_MUTEX internals_; + /// true when event persistence qos is guaranteed + bool is_safe_; + /// signalled when is_safe_ goes true + ACE_SYNCH_CONDITION until_safe_; + + /// Smart pointer to this object + /// Provides continuity between smart pointers and "Routing_Slip::this" + /// Also lets the Routing_Slip manage its own minimum lifetime. + Routing_Slip_Ptr this_ptr_; + + // The event being delivered. + TAO_Notify_Event_Ptr event_; + + /// A mini-state machine to control persistence + /// See external doc for circles and arrows. + enum State + { + rssCREATING, + rssTRANSIENT, + rssRELOADED, + rssNEW, + rssCOMPLETE_WHILE_NEW, + rssSAVING, + rssSAVED, + rssUPDATING, + rssCHANGED_WHILE_SAVING, + rssCHANGED, + rssCOMPLETE, + rssDELETING, + rssTERMINAL + } state_; + + /// A collection of delivery requests + Delivery_Request_Vec delivery_requests_; + + /// Methods that should be restarted during event recovery + Delivery_Method_Vec delivery_methods_; + + /// How many delivery requests are complete + size_t complete_requests_; + + /// Pointer to a Routing_Slip_Persistence_Manager + Routing_Slip_Persistence_Manager * rspm_; + + int sequence_; + + static TAO_SYNCH_MUTEX sequence_lock_; + static int routing_slip_sequence_; + static size_t count_enter_transient_; + static size_t count_continue_transient_; + static size_t count_enter_reloaded_; + static size_t count_enter_new_; + static size_t count_continue_new_; + static size_t count_enter_complete_while_new_; + static size_t count_enter_saving_; + static size_t count_enter_saved_; + static size_t count_enter_updating_; + static size_t count_enter_changed_while_saving_; + static size_t count_continue_changed_while_saving_; + static size_t count_enter_changed_; + static size_t count_continue_changed_; + static size_t count_enter_complete_; + static size_t count_enter_deleting_; + static size_t count_enter_terminal_; + + static Routing_Slip_Queue persistent_queue_; +}; + +} // namespace + +#if defined (__ACE_INLINE__) +#include "Routing_Slip.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/post.h" +#endif /* TAO_NOTIFY_ROUTING_SLIP_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.cpp b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.cpp new file mode 100644 index 00000000000..dfb67f4f7ec --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.cpp @@ -0,0 +1,803 @@ +// $Id$ + +#include "Routing_Slip_Persistence_Manager.h" +#include "Standard_Event_Persistence.h" +#include "Persistent_File_Allocator.h" + +namespace TAO_NOTIFY +{ + +Routing_Slip_Persistence_Manager::Routing_Slip_Persistence_Manager( + Standard_Event_Persistence_Factory* factory) + : removed_(false) + , serial_number_(0) + , allocator_(factory->allocator()) + , factory_(factory) + , first_event_block_(0) + , first_routing_slip_block_(0) + , callback_(0) + , event_mb_ (0) + , routing_slip_mb_(0) +{ + this->prev_manager_ = this; + this->next_manager_ = this; +} + +Routing_Slip_Persistence_Manager::~Routing_Slip_Persistence_Manager() +{ + ACE_ASSERT(this->prev_manager_ == this); + ACE_ASSERT(this->next_manager_ == this); + delete this->first_event_block_; + this->first_event_block_ = 0; + delete this->first_routing_slip_block_; + this->first_routing_slip_block_ = 0; + delete this->event_mb_; + this->event_mb_ = 0; + delete this->routing_slip_mb_; + this->routing_slip_mb_ = 0; +} + +void +Routing_Slip_Persistence_Manager::set_callback(Persistent_Callback* callback) +{ + ACE_GUARD(ACE_SYNCH_MUTEX, ace_mon, this->lock_); + this->callback_ = callback; +} + +bool +Routing_Slip_Persistence_Manager::store_root() +{ + bool result = false; + + this->factory_->get_preallocated_pointer ( + this->routing_slip_header_.next_serial_number, + this->routing_slip_header_.next_routing_slip_block); + + // we should already have a psb, but JIC + ACE_ASSERT(this->first_routing_slip_block_ != 0); + ACE_ASSERT(this->first_routing_slip_block_->block_number() == + ROUTING_SLIP_ROOT_BLOCK_NUMBER); + + // Don't take any chances. Use hard-wired root serial number. + this->routing_slip_header_.serial_number = ROUTING_SLIP_ROOT_SERIAL_NUMBER; + + // This will eventually break after something like 58000 years. + // At such time we should change this to !=. + ACE_ASSERT(this->routing_slip_header_.next_serial_number > + ROUTING_SLIP_ROOT_SERIAL_NUMBER); + + ACE_Message_Block versioninfo(2); + versioninfo.wr_ptr()[0] = 1; // Major version number + versioninfo.wr_ptr()[1] = 0; // Minor version number + versioninfo.wr_ptr(2); + ACE_GUARD_RETURN(ACE_SYNCH_MUTEX, ace_mon, this->lock_, result); + result = this->build_chain(this->first_routing_slip_block_, + this->routing_slip_header_, this->allocated_routing_slip_blocks_, + versioninfo); + if (result) + { + this->routing_slip_header_.put_header(*this->first_routing_slip_block_); + this->allocator_->write(this->first_routing_slip_block_); + } + return result; +} + +bool +Routing_Slip_Persistence_Manager::reload( + ACE_Message_Block*& event, + ACE_Message_Block*& routing_slip) +{ + bool result = false; + if (this->event_mb_ != 0 && this->routing_slip_mb_ != 0) + { + event = this->event_mb_; + this->event_mb_ = 0; + routing_slip = this->routing_slip_mb_; + this->routing_slip_mb_ = 0; + result = true; + } + else + { + event = 0; + routing_slip = 0; + } + return result; +} + +bool +Routing_Slip_Persistence_Manager::load( + Block_Number block_number, + Block_Serial_Number expected_serial_number) +{ + /** + * NOTE: There is no need to worry about guarding anything. We assume + * that there will be one and only one thread doing the entire + * reload process. + */ + bool result = false; + size_t block_size = this->allocator_->block_size(); + this->first_routing_slip_block_ = + this->allocator_->allocate_at(block_number); + this->first_routing_slip_block_->set_allocator_owns(false); + this->first_routing_slip_block_->set_sync(); + + this->serial_number_ = expected_serial_number; + + ACE_NEW_NORETURN(this->routing_slip_mb_, ACE_Message_Block(block_size)); + ACE_NEW_NORETURN(this->event_mb_, ACE_Message_Block(block_size)); + if (this->event_mb_ != 0 && this->routing_slip_mb_ != 0) + { + if (this->reload_chain( + this->first_routing_slip_block_, + this->routing_slip_header_, + this->allocated_routing_slip_blocks_, + this->routing_slip_mb_, + expected_serial_number)) + { + if (this->routing_slip_header_.event_block != 0) + { + this->first_event_block_ = this->allocator_->allocate_at( + this->routing_slip_header_.event_block); + result = this->reload_chain( + this->first_event_block_, + this->event_header_, + this->allocated_event_blocks_, + this->event_mb_, + 0); + } + else if (block_number == ROUTING_SLIP_ROOT_BLOCK_NUMBER) + { + // only the root can lack event + result = true; + } + else + { + ACE_ERROR((LM_ERROR, + ACE_TEXT( + "(%P|%t) Reloaded Persistent Event is missing event.\n") + )); + } + } + } + if (! result) + { + delete this->routing_slip_mb_; + this->routing_slip_mb_ = 0; + delete this->event_mb_; + this->event_mb_ = 0; + } + return result; +} + +Routing_Slip_Persistence_Manager * +Routing_Slip_Persistence_Manager::load_next () +{ + Routing_Slip_Persistence_Manager * result; + ACE_NEW_RETURN(result, Routing_Slip_Persistence_Manager (this->factory_), 0); + + if (result->load(this->routing_slip_header_.next_routing_slip_block, + this->routing_slip_header_.next_serial_number)) + { + result->dllist_push_back(); + } + else + { + // steal the psb for use as the next psb. + // delete the rspm. We'll create another one later. + Persistent_Storage_Block * next_psb = result->first_routing_slip_block_; + result->first_routing_slip_block_ = 0; +// next_psb->set_allocator_owns(true); + this->factory_->done_reloading ( + next_psb, + result->serial_number_); + delete result; + result = 0; + } + return result; +} + +bool +Routing_Slip_Persistence_Manager::store(const ACE_Message_Block& event, + const ACE_Message_Block& routing_slip) +{ + bool result = false; + ACE_GUARD_RETURN(ACE_SYNCH_MUTEX, ace_mon, this->lock_, result); + if (!this->removed_) + { + result = store_i(event, routing_slip); + } + return result; +} + +bool +Routing_Slip_Persistence_Manager::update(const ACE_Message_Block& routing_slip) +{ + bool result = false; + ACE_GUARD_RETURN(ACE_SYNCH_MUTEX, ace_mon, this->lock_, result); + // If we have not gotten the event yet or we have no allocator, fail + if (!this->removed_) + { + if (this->persisted()) + { + result = update_i(routing_slip); + } + } + return result; +} + +bool +Routing_Slip_Persistence_Manager::remove() +{ + bool result = false; + ACE_GUARD_RETURN(ACE_SYNCH_MUTEX, ace_mon, this->lock_, result); + // Assert that this is in the dllist + ACE_ASSERT(this->prev_manager_ != this); + ACE_ASSERT(this->persisted()); + Routing_Slip_Persistence_Manager* prev = this->prev_manager_; + // Once our previous manager removes us, we can deallocate in any order + this->factory_->lock.acquire(); + this->remove_from_dllist(); + result = prev->update_next_manager(this); + this->factory_->lock.release(); + size_t block_number = 0; + if (this->first_routing_slip_block_ != 0) + { + this->allocator_->free(this->first_routing_slip_block_->block_number()); + delete this->first_routing_slip_block_; + this->first_routing_slip_block_ = 0; + } + if (this->first_event_block_ != 0) + { + this->allocator_->free(this->first_event_block_->block_number()); + delete this->first_event_block_; + this->first_event_block_ = 0; + } + while (this->allocated_routing_slip_blocks_.pop(block_number) == 0) + { + this->allocator_->free(block_number); + } + while (this->allocated_event_blocks_.pop(block_number) == 0) + { + this->allocator_->free(block_number); + } + this->removed_ = true; + Persistent_Storage_Block* callbackblock = + this->allocator_->allocate_nowrite(); + callbackblock->set_callback(this->callback_); + result &= this->allocator_->write(callbackblock); + return result; +} + +Routing_Slip_Persistence_Manager::Block_Header::Block_Header(Header_Type type) + : serial_number (0) + , next_overflow(0) + , header_type (ACE_static_cast (Block_Type, type)) + , data_size(0) +{ +} + +size_t +Routing_Slip_Persistence_Manager::Block_Header::extract_header( + Persistent_Storage_Block& psb, const size_t offset) +{ + size_t pos = offset; + unsigned char* data = psb.data(); + + serial_number = data[pos++]; + serial_number = (serial_number << 8) + data[pos++]; + serial_number = (serial_number << 8) + data[pos++]; + serial_number = (serial_number << 8) + data[pos++]; + serial_number = (serial_number << 8) + data[pos++]; + serial_number = (serial_number << 8) + data[pos++]; + serial_number = (serial_number << 8) + data[pos++]; + serial_number = (serial_number << 8) + data[pos++]; + + next_overflow = data[pos++]; + next_overflow = (next_overflow << 8) + data[pos++]; + next_overflow = (next_overflow << 8) + data[pos++]; + next_overflow = (next_overflow << 8) + data[pos++]; + + header_type = data[pos++]; + header_type = (data_size << 8) + data[pos++]; + + data_size = data[pos++]; + data_size = (data_size << 8) + data[pos++]; + return pos; +} + +size_t +Routing_Slip_Persistence_Manager::Block_Header::put_header( + Persistent_Storage_Block& psb, size_t offset) +{ + // Assume that our psb can hold our small amount of data... + size_t pos = offset; + unsigned char* data = psb.data(); + // Store serial_number + data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 56) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 48) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 40) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 32) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 24) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 16) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 8) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (serial_number >> 0) & 0xff); + // Store next_overflow + data[pos++] = next_overflow >> 24; + data[pos++] = (next_overflow >> 16) & 0xff; + data[pos++] = (next_overflow >> 8) & 0xff; + data[pos++] = next_overflow & 0xff; + // Store header_type + data[pos++] = (header_type >> 8) & 0xff; + data[pos++] = header_type & 0xff; + // Store data_size + data[pos++] = (data_size >> 8) & 0xff; + data[pos++] = data_size & 0xff; + + return pos; +} + +Routing_Slip_Persistence_Manager::Routing_Slip_Header::Routing_Slip_Header() + : Block_Header (BT_Event) + , next_routing_slip_block(0) + , next_serial_number(0) + , event_block(0) +{ +} + +size_t +Routing_Slip_Persistence_Manager::Routing_Slip_Header::extract_header( + Persistent_Storage_Block& psb, const size_t offset) +{ + size_t pos = offset; + pos = this->Block_Header::extract_header(psb, pos); + unsigned char* data = psb.data(); + next_routing_slip_block = data[pos++]; + next_routing_slip_block = (next_routing_slip_block << 8) + data[pos++]; + next_routing_slip_block = (next_routing_slip_block << 8) + data[pos++]; + next_routing_slip_block = (next_routing_slip_block << 8) + data[pos++]; + next_serial_number = data[pos++]; + next_serial_number = (next_serial_number << 8) + data[pos++]; + next_serial_number = (next_serial_number << 8) + data[pos++]; + next_serial_number = (next_serial_number << 8) + data[pos++]; + next_serial_number = (next_serial_number << 8) + data[pos++]; + next_serial_number = (next_serial_number << 8) + data[pos++]; + next_serial_number = (next_serial_number << 8) + data[pos++]; + next_serial_number = (next_serial_number << 8) + data[pos++]; + event_block = data[pos++]; + event_block = (event_block << 8) + data[pos++]; + event_block = (event_block << 8) + data[pos++]; + event_block = (event_block << 8) + data[pos++]; + return pos; +} + +size_t +Routing_Slip_Persistence_Manager::Routing_Slip_Header::put_header( + Persistent_Storage_Block& psb, const size_t offset) +{ + // Assume that our psb can hold our small amount of data... + size_t pos = offset; + // Store serial number, next_overflow and data_size + pos = this->Block_Header::put_header(psb, pos); + + unsigned char* data = psb.data(); + // Store next_routing_slip_block + data[pos++] = next_routing_slip_block >> 24; + data[pos++] = (next_routing_slip_block >> 16) & 0xff; + data[pos++] = (next_routing_slip_block >> 8) & 0xff; + data[pos++] = next_routing_slip_block & 0xff; + // Store serial_number + data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 56) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 48) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 40) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 32) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 24) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 16) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 8) & 0xff); + data[pos++] = ACE_static_cast (unsigned char, (next_serial_number >> 0) & 0xff); + // Store event_block + data[pos++] = event_block >> 24; + data[pos++] = (event_block >> 16) & 0xff; + data[pos++] = (event_block >> 8) & 0xff; + data[pos++] = event_block & 0xff; + return pos; +} + +Routing_Slip_Persistence_Manager::Overflow_Header::Overflow_Header () + : Block_Header (BT_Overflow) +{ +} + +Routing_Slip_Persistence_Manager::Event_Header::Event_Header () + : Block_Header (BT_Routing_Slip) +{ +} + +bool +Routing_Slip_Persistence_Manager::store_i(const ACE_Message_Block& event, + const ACE_Message_Block& routing_slip) +{ + bool result = false; + + bool initially_persisted = this->persisted(); + if (!initially_persisted) + { + this->factory_->lock.acquire(); + this->factory_->preallocate_next_record(this->serial_number_, + this->first_routing_slip_block_, + this->routing_slip_header_.next_serial_number, + this->routing_slip_header_.next_routing_slip_block); + this->routing_slip_header_.serial_number = this->serial_number_; + } + + result = this->build_chain(this->first_routing_slip_block_, + this->routing_slip_header_, this->allocated_routing_slip_blocks_, + routing_slip); + + if (result) + { + // No need for a callback here since we do our own below + result &= this->store_event(event); + // If we have an event block allocated, update our header + if (this->first_event_block_ != 0) + { + this->routing_slip_header_.event_block = + this->first_event_block_->block_number(); + } + else + { + ACE_ERROR((LM_ERROR, + ACE_TEXT( + "(%P|%t) No Event is being stored with this routing slip.\n") + )); + } + // Always write our first block out. + this->dllist_push_back(); + result &= (this->write_first_routing_slip_block() != 0); + // because the first rs blocks everywhere have been given sync, we are + // guaranteed that they will be totally written by the time we get to this + // empty callback-only block. + Persistent_Storage_Block* callbackblock = + this->allocator_->allocate_nowrite(); + callbackblock->set_callback(this->callback_); + result &= this->allocator_->write(callbackblock); + } + if (!initially_persisted) + { + this->factory_->lock.release(); + } + return result; +} + +bool +Routing_Slip_Persistence_Manager::update_i( + const ACE_Message_Block& routing_slip) +{ + bool result = true; + size_t routing_slip_size = routing_slip.total_length(); + if (routing_slip_size != 0) + { + result = this->build_chain(this->first_routing_slip_block_, + this->routing_slip_header_, this->allocated_routing_slip_blocks_, + routing_slip); + + result &= this->allocator_->write(this->first_routing_slip_block_); + } + Persistent_Storage_Block* callbackblock = + this->allocator_->allocate_nowrite(); + callbackblock->set_callback(this->callback_); + result &= this->allocator_->write(callbackblock); + return result; +} + +bool +Routing_Slip_Persistence_Manager::store_event( + const ACE_Message_Block& event) +{ + bool result = true; + size_t event_size = event.total_length(); + if (event_size != 0) + { + if (this->first_event_block_ == 0) + { + this->first_event_block_ = this->allocator_->allocate(); + this->first_event_block_->set_allocator_owns(false); + } + + result = this->build_chain(this->first_event_block_, + this->event_header_, this->allocated_event_blocks_, + event); + + result &= this->allocator_->write(this->first_event_block_); + } + return result; +} + +size_t +Routing_Slip_Persistence_Manager::fill_block(Persistent_Storage_Block& psb, + const size_t offset_into_block, const ACE_Message_Block* data, + const size_t offset_into_msg) +{ + unsigned char* ptr = (unsigned char*)data->rd_ptr(); + return this->fill_block(psb, offset_into_block, ptr + offset_into_msg, + data->length() - offset_into_msg); +} + +size_t +Routing_Slip_Persistence_Manager::fill_block(Persistent_Storage_Block& psb, + const size_t offset_into_block, unsigned char* data, const size_t data_size) +{ + size_t result = 0; + if (data_size > 0) + { + const size_t max_size = this->allocator_->block_size() - offset_into_block; + size_t size_to_copy = data_size; + if (size_to_copy > max_size) + { + size_to_copy = max_size; + result = data_size - size_to_copy; + } + else + { + result = 0; + } + ACE_OS::memcpy(psb.data() + offset_into_block, data, size_to_copy); + } + return result; +} + +bool +Routing_Slip_Persistence_Manager::build_chain( + Persistent_Storage_Block* first_block, Block_Header& first_header, + ACE_Unbounded_Stack<size_t>& allocated_blocks, + const ACE_Message_Block& data) +{ + size_t data_size = data.total_length(); + size_t remainder = data_size; + bool result = true; + // Save the number of items currently on the allocation list for + ACE_Unbounded_Stack<size_t> blocks_to_free; + size_t block_number = 0; + + // reverse the order so when we pop, we free up things closer to block 0 + // first + while (allocated_blocks.pop(block_number) == 0) + { + blocks_to_free.push(block_number); + } + size_t pos = first_header.put_header( + *first_block); + const ACE_Message_Block* mblk = &data; + remainder = this->fill_block(*first_block, pos, mblk, 0); + while ((remainder == 0) && (mblk->cont() != 0)) + { + pos += mblk->length(); + mblk = mblk->cont(); + remainder = this->fill_block(*first_block, pos, mblk, 0); + } + first_header.data_size = data_size - remainder; + first_header.next_overflow = 0; + + Block_Header* prevhdr = &first_header; + Persistent_Storage_Block* prevblk = first_block; + + while (remainder > 0) + { + Overflow_Header* hdr = 0; + ACE_NEW_RETURN(hdr, Overflow_Header, result); + + Persistent_Storage_Block* curblk = this->allocator_->allocate(); + allocated_blocks.push(curblk->block_number()); + // Set the previous block's overflow "pointer" to us. + prevhdr->next_overflow = curblk->block_number(); + prevhdr->put_header(*prevblk); + pos = hdr->put_header(*curblk); + hdr->data_size = remainder; + + size_t offset_into_msg = mblk->length() - remainder; + remainder = this->fill_block(*curblk, pos, mblk, offset_into_msg); + while ((remainder == 0) && (mblk->cont() != 0)) + { + pos += mblk->length(); + mblk = mblk->cont(); + remainder = this->fill_block(*curblk, pos, mblk, 0); + } + + hdr->data_size -= remainder; + if (prevblk != first_block) + { + // allocator obtains ownership, so write out and delete the header + // only. + result &= this->allocator_->write(prevblk); + delete prevhdr; + } + prevblk = curblk; + prevhdr = hdr; + } + if (prevblk != first_block) + { + prevhdr->put_header(*prevblk); + result &= this->allocator_->write(prevblk); + delete prevhdr; + } + pos = first_header.put_header( + *first_block); + // Free all but the first routing_slip_block + while (blocks_to_free.pop(block_number) == 0) + { + this->allocator_->free(block_number); + } + + return result; +} + +bool +Routing_Slip_Persistence_Manager::reload_chain( + Persistent_Storage_Block* first_block, Block_Header& first_header, + ACE_Unbounded_Stack<size_t>& allocated_blocks, + ACE_Message_Block* amb, + ACE_UINT64 expected_serial_number + ) +{ + bool result = false; + size_t block_size = this->allocator_->block_size(); + if (this->allocator_->read(first_block)) + { + size_t pos = 0; + size_t nextptr = 0; + ACE_Message_Block* mbptr = amb; + ACE_Message_Block* mbnew = 0; + + pos = first_header.extract_header(*first_block); + if (first_header.serial_number == expected_serial_number) + { + // We have to copy the first block because we cache it. + ACE_OS::memcpy(mbptr->wr_ptr(), first_block->data(), + block_size); + mbptr->rd_ptr(pos); + mbptr->wr_ptr(pos + first_header.data_size); + nextptr = first_header.next_overflow; + while (nextptr != 0) + { + Overflow_Header overflow_header; + ACE_NEW_RETURN(mbnew, ACE_Message_Block(block_size), result); + mbptr->cont(mbnew); + Persistent_Storage_Block* psb = this->allocator_->allocate_at(nextptr); + mbptr = mbnew; + // Deallocate the PSB's data and reallocate it to our wr_ptr()... + psb->reassign_data(ACE_static_cast(unsigned char*, + ACE_static_cast(void*, mbptr->wr_ptr())), true); + // ...read into the PSB (whose data is inside of the AMB)... + this->allocator_->read(psb); + allocated_blocks.push(psb->block_number()); + // ...extract all headers so we know the data's size... + pos = overflow_header.extract_header(*psb); + // ...set up the region that somebody else can look at... + mbptr->rd_ptr(pos); + mbptr->wr_ptr(pos + overflow_header.data_size); + // ...then make sure we don't delete data since we don't own it. + psb->reassign_data(0); + delete psb; + nextptr = overflow_header.next_overflow; + } + result = true; + } + } + return result; +} + +bool +Routing_Slip_Persistence_Manager::update_next_manager( + Routing_Slip_Persistence_Manager* next) +{ + bool result = false; + ACE_GUARD_RETURN(ACE_SYNCH_MUTEX, ace_mon, this->lock_, result); + ACE_ASSERT(this->persisted()); + if (!this->removed_) + { + bool updated = false; + if (this->next_manager_ != 0) + { + if (this->routing_slip_header_.next_serial_number != + next->routing_slip_header_.next_serial_number) + { + this->routing_slip_header_.next_serial_number = + next->routing_slip_header_.next_serial_number; + updated = true; + } + if (this->routing_slip_header_.next_routing_slip_block != + next->routing_slip_header_.next_routing_slip_block) + { + this->routing_slip_header_.next_routing_slip_block = + next->routing_slip_header_.next_routing_slip_block; + updated = true; + } + } + if (updated) + { + this->write_first_routing_slip_block(); + } + } + return result; +} + +bool +Routing_Slip_Persistence_Manager::persisted() +{ + return (0 != this->first_routing_slip_block_); +} + +bool +Routing_Slip_Persistence_Manager::is_root () const +{ + return this->serial_number_ == ROUTING_SLIP_ROOT_SERIAL_NUMBER; +} + +void +Routing_Slip_Persistence_Manager::release_all () +{ + ACE_ASSERT(is_root()); + while (this->next_manager_ != this) + { + Routing_Slip_Persistence_Manager * next = this->next_manager_; + next->remove_from_dllist(); + ACE_ASSERT(next != this->next_manager_); + delete next; + } +} + +size_t +Routing_Slip_Persistence_Manager::write_first_routing_slip_block( + bool prepare_only) +{ + size_t pos = this->routing_slip_header_.put_header( + *this->first_routing_slip_block_); + if (!prepare_only) + { + this->allocator_->write(this->first_routing_slip_block_); + } + return pos; +} + +void +Routing_Slip_Persistence_Manager::dllist_push_back() +{ + insert_before (&this->factory_->root()); +} + +void +Routing_Slip_Persistence_Manager::insert_before (Routing_Slip_Persistence_Manager * node) +{ + // Since this is a private function, the caller should have done locking + // on the factory before calling here. The same is true for removals. + ACE_ASSERT(this->prev_manager_ == this); + ACE_ASSERT(this->next_manager_ == this); + ACE_ASSERT(node != this); + this->prev_manager_ = node->prev_manager_; + node->prev_manager_ = this; + this->next_manager_ = node; + this->prev_manager_->next_manager_ = this; +} + +void +Routing_Slip_Persistence_Manager::remove_from_dllist() +{ + // Since this is a private function, the caller should have done locking + // on the factory before calling here. The same is true for insertions. + ACE_ASSERT(this->persisted()); + ACE_ASSERT(this->prev_manager_ != this); + ACE_ASSERT(this->next_manager_ != this); + this->prev_manager_->next_manager_ = this->next_manager_; + this->next_manager_->prev_manager_ = this->prev_manager_; + this->prev_manager_ = this; + this->next_manager_ = this; +} + +} /* namespace TAO_NOTIFY */ + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +//template class ACE_Node<size_t>; +//template class ACE_Unbounded_Stack<size_t>; +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +//#pragma instantiate ACE_Node<size_t> +//#pragma instantiate ACE_Unbounded_Stack<size_t> +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.h b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.h new file mode 100644 index 00000000000..b425fa71152 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Persistence_Manager.h @@ -0,0 +1,264 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Routing_Slip_Persistence_Manager.h + * + * $Id$ + * + * A Routing_Slip_Persistence manager controls the actual allocation of + * blocks through a Persistent_Storage_Allocator and can persist an + * event and its routing slip. + * + * @author Jonathan Pollack <pollack_j@ociweb.com> + */ +//============================================================================= + +#ifndef ROUTING_SLIP_PERSISTENCE_MANAGER_H +#define ROUTING_SLIP_PERSISTENCE_MANAGER_H +#include /**/ "ace/pre.h" +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "notify_export.h" +#include "ace/Message_Block.h" +#include "ace/Synch_T.h" +#include "ace/Containers_T.h" + +namespace TAO_NOTIFY +{ + +// Some forward declarations. +class TAO_Notify_Export Standard_Event_Persistence_Factory; +class TAO_Notify_Export Persistent_File_Allocator; +class TAO_Notify_Export Persistent_Storage_Block; +class TAO_Notify_Export Persistent_Callback; + +/** + * \brief Manage interaction between Routing_Slip and persistent storage. + * + * todo: to complete the strategization of event persistent storage this + * should become an interface that is implemented differently by different + * strategies. For now it interacts with Standard_Event_Persistence. + */ +class TAO_Notify_Export Routing_Slip_Persistence_Manager +{ +public: + /// A unique identifier for logical blocks in persistent storage. + typedef ACE_UINT64 Block_Serial_Number; + /// The physical address of a block in persistent storage. + typedef ACE_UINT32 Block_Number; + /// The size of a block in persistent storage. + typedef ACE_UINT16 Block_Size; + /// A code to indicate the type of block in persistent storage. + typedef ACE_UINT16 Block_Type; + + /// The constructor. + /// We must have one allocator per Persistent_File, and it has to be + /// passed in here. + Routing_Slip_Persistence_Manager(Standard_Event_Persistence_Factory* factory); + + /// The destructor. + ~Routing_Slip_Persistence_Manager(); + + /// Set up callbacks + void set_callback(Persistent_Callback* callback); + + + /// Store an event + routing slip. + bool store(const ACE_Message_Block& event, + const ACE_Message_Block& routing_slip); + + /// \brief Update the routing slip. + /// + /// We must always overwrite the first block + /// last, and it may not chance. Other blocks should be freed and + /// reallocated. + bool update(const ACE_Message_Block& routing_slip); + + /// \brief Remove our associated event and routing slip from the + /// Persistent_File_Allocator. + bool remove(); + + ///////////////////////////////////////// + // Methods to be used during reload only. + + /// \brief Call this method to recover data during event reload. + /// + /// It should not fail under normal circumstances. + /// Caller owns the resulting message blocks and is responsible + /// for deleting them. + /// Reload the event and routing_slip from the Persistent_File_Allocator. + bool reload(ACE_Message_Block*& event, ACE_Message_Block*&routing_slip); + + /// \brief Get next RSPM during reload. + /// + /// After using the data from the reload method, call this + /// method to get the next RSPM. It returns a null pointer + /// when all persistent events have been reloaded. + Routing_Slip_Persistence_Manager * load_next (); + + ///////////////////////// + // Implementation methods. + // Should not be called by Routing_Slip + + /// \brief Commit root data to disk, which should only be done for a root node. + bool store_root(); + + /// \brief Reload data into this RSPM from the given block/serial# + /// + /// \return false if the reload is not successful. + bool load(Block_Number block_number, Block_Serial_Number expected_serial_number); + + /// \brief Is this RSPM attached to the root block? + bool is_root () const; + + /// \brief During cleanup for shut down, release all chained RSPMs. + void release_all (); + +private: + /** + * \brief private: Storage for header information of all persistent block. + */ + class Block_Header + { + public: + enum Header_Type { + BT_Routing_Slip, + BT_Event, + BT_Overflow + }; + + Block_Header(Header_Type type); + virtual size_t extract_header(Persistent_Storage_Block& psb, + const size_t offset = 0); + virtual size_t put_header(Persistent_Storage_Block& psb, + const size_t offset = 0); + + public: + /// Our serial number + Block_Serial_Number serial_number; + /// Address of the overflow record (if any) + Block_Number next_overflow; + /// How much extra header data is in this block (not including this header) + Block_Type header_type; + /// How much actual data is in this block? (not including headers) + Block_Size data_size; + }; + + /** + * \brief private: Storage for header information for Routing_Slip blocks. + */ + class Routing_Slip_Header : public Block_Header + { + public: + Routing_Slip_Header(); + virtual size_t extract_header(Persistent_Storage_Block& psb, + const size_t offset = 0); + virtual size_t put_header(Persistent_Storage_Block& psb, + const size_t offset = 0); + + public: + /// The next event in the system + Block_Number next_routing_slip_block; + /// The next expected serial number + Block_Serial_Number next_serial_number; + Block_Number event_block; + }; + + /// \brief An Event block header. + /// + /// is just a Block_Header with no extra data + class Event_Header : public Block_Header + { + public: + Event_Header (); + }; + + /// \brief An overflow block header. + /// + /// is just a Block_Header with no extra data + /// The same record type is used for both Routing_Slip + /// and Event overflows. + class Overflow_Header : public Block_Header + { + public: + Overflow_Header (); + }; + + bool store_i(const ACE_Message_Block& event, + const ACE_Message_Block& routing_slip); + + bool update_i(const ACE_Message_Block& routing_slip); + + bool store_event(const ACE_Message_Block& event); + + /// Fill in a block with data, and return the number of bytes + /// of data remaining to be written. + size_t fill_block(Persistent_Storage_Block& psb, + const size_t offset_into_block, const ACE_Message_Block* data, + const size_t offset_into_msg); + size_t fill_block(Persistent_Storage_Block& psb, + const size_t offset_into_block, unsigned char* data, + const size_t data_size); + + /// Build a chain of Persistent_Storage_Blocks + bool build_chain( + Persistent_Storage_Block* first_block, + Block_Header& first_header, + ACE_Unbounded_Stack<size_t>& allocated_blocks, + const ACE_Message_Block& data); + + /// Reload a chain from persistent store. + bool reload_chain(Persistent_Storage_Block* first_block, + Block_Header& first_header, + ACE_Unbounded_Stack<size_t>& allocated_blocks, + ACE_Message_Block* amb, + ACE_UINT64 expected_serial_number); + + /// Locked method to do the work of setting the next_manager_. + bool update_next_manager(Routing_Slip_Persistence_Manager* next); + + /// Have we been persisted yet? + bool persisted(); + + /// Write out our first event block. + size_t write_first_routing_slip_block(bool prepare_only = false); + + /// Insert ourselves into a linked list of Routing_Slip_Persistnce_Managers + void dllist_push_back(); + + void insert_before (Routing_Slip_Persistence_Manager * node); + + /// Remove ourselves from a linked list of Routing_Slip_Persistence_Managers + void remove_from_dllist(); + +private: + ACE_SYNCH_MUTEX lock_; + bool removed_; + ACE_UINT64 serial_number_; + Persistent_File_Allocator* allocator_; + Standard_Event_Persistence_Factory* factory_; + Event_Header event_header_; + Routing_Slip_Header routing_slip_header_; + Persistent_Storage_Block* first_event_block_; + Persistent_Storage_Block* first_routing_slip_block_; + /// We are part of a doubly-linked list + Routing_Slip_Persistence_Manager* prev_manager_; + Routing_Slip_Persistence_Manager* next_manager_; + ACE_Unbounded_Stack<size_t> allocated_event_blocks_; + ACE_Unbounded_Stack<size_t> allocated_routing_slip_blocks_; + Persistent_Callback* callback_; + + /// if these are non-zero we own 'em + ACE_Message_Block * event_mb_; + ACE_Message_Block * routing_slip_mb_; +}; + +} /* namespace TAO_NOTIFY */ + +#include /**/ "ace/post.h" +#endif /* ROUTING_SLIP_PERSISTENCE_MANAGER_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.cpp b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.cpp new file mode 100644 index 00000000000..4ca7d08ebb9 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.cpp @@ -0,0 +1,120 @@ +// $Id$ + +#include "Routing_Slip_Queue.h" + +#if ! defined (__ACE_INLINE__) +#include "Routing_Slip_Queue.inl" +#endif /* __ACE_INLINE__ */ + +#include "tao/debug.h" +#include "ace/Dynamic_Service.h" + +//#define DEBUG_LEVEL 9 +#define DEBUG_LEVEL TAO_debug_level + +namespace TAO_NOTIFY +{ + Routing_Slip_Queue::Routing_Slip_Queue (size_t allowed) + : allowed_ (allowed) + , active_ (0) + { + } + + Routing_Slip_Queue::~Routing_Slip_Queue () + { + } + + void + Routing_Slip_Queue::add (const Routing_Slip_Ptr & routing_slip) + { + Guard guard (internals_); + ACE_ASSERT (guard.locked()); // check recursion + if (this->allowed_ == 0) + { + ++this->active_; + guard.release (); + routing_slip->at_front_of_persist_queue (); +// guard.acquire (); + } + else + { + this->queue_.enqueue_tail (routing_slip); + dispatch (guard); + } + } + + void Routing_Slip_Queue::complete () + { + Guard guard (internals_); + ACE_ASSERT (guard.locked()); // check recursion + ACE_ASSERT (this->active_ > 0); + --this->active_; + dispatch (guard); + } + + void + Routing_Slip_Queue::dispatch (Guard & guard) + { + // we start out pretty nice, + // but the more work we do for other people + // the less nice we get. + size_t nice = this->allowed_ + 1; + while (nice > 0 && (this->active_ < this->allowed_)) + { + if (dispatch_one (guard)) + { + --nice; + } + else + { + // that's about as nice as I get. + nice = 0; + } + } + } + + bool + Routing_Slip_Queue::dispatch_one (Guard & guard) + { + bool ok = false; + Routing_Slip_Ptr routing_slip; + if (this->queue_.dequeue_head (routing_slip) == 0) + { + ++this->active_; + guard.release (); + routing_slip->at_front_of_persist_queue (); + guard.acquire (); + } + return ok; + } + + void + Routing_Slip_Queue::set_allowed (size_t allowed) + { + Guard guard (internals_); + size_t allowed_was = this->allowed_; + this->allowed_ = allowed; + if (allowed == 0 && allowed_was != 0) + { + while (dispatch_one (guard)) + { + ; // work happens in dispatc_one + } + } + else + { + dispatch (guard); + } + } +} // namespace + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +template class ACE_Node<TAO_NOTIFY::Routing_Slip_Ptr>; +template class ACE_Unbounded_Queue<TAO_NOTIFY::Routing_Slip_Ptr>; +template class ACE_Unbounded_Queue_Iterator<TAO_NOTIFY::Routing_Slip_Ptr>; +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#pragma instantiate ACE_Node<TAO_NOTIFY::Routing_Slip_Ptr> +#pragma instantiate ACE_Unbounded_Queue<TAO_NOTIFY::Routing_Slip_Ptr> +#pragma instantiate ACE_Unbounded_Queue_Iterator<TAO_NOTIFY::Routing_Slip_Ptr> +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ + diff --git a/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.h b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.h new file mode 100644 index 00000000000..93ddab1b713 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Routing_Slip_Queue.h @@ -0,0 +1,92 @@ +/* -*- C++ -*- */ +// $Id$ + +#ifndef TAO_NOTIFY_ROUTING_SLIP_QUEUE_H +#define TAO_NOTIFY_ROUTING_SLIP_QUEUE_H +#include "ace/pre.h" + +#include "Routing_Slip.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace TAO_NOTIFY +{ + /** + * \brief A queue of Routing_Slips waiting to be persisted. + * + * The Routing_Slip_Queue keeps a queue of Routing_Slips waiting + * to be written to persistent storage. The "allowed" parameter + * determines how many Routing_Slips can be handled simultaneously + * by the persistent storage. Until this threshold is reached, + * Routing_Slips are not held in the queue, but pass straight through. + * + * Once the allowe number of Routing_Slips are being handled, any + * additional requests are held in the queue until persistence is + * complete for another Routing_Slips. + * + * Having Routing_Slips waiting in the queue is "a good thing" [TM] + * because it allows delivery completions to be applied to the + * routing slip before it is written -- thereby reducing or completely + * eliminating the number of actual writes to persistent storage. + * + * Experimentation indicates that a good value for "allowed" is 1. + * + * Allowed == 0 is treated as a special case meaning pass all Routing_Slips + * through the queue immediately. Setting it a good way to test how well + * your storage device withstands continuous beating. + */ + class TAO_Notify_Export Routing_Slip_Queue + { + typedef ACE_Unbounded_Queue <Routing_Slip_Ptr> Queue; + typedef ACE_Guard< TAO_SYNCH_MUTEX > Guard; + public: + /** + * \brief Construct setting "allowed". + * \param allowed the number of Routing_Slips that can be handled + * simultaneously by the persistent store. + */ + Routing_Slip_Queue (size_t allowed = 1); + /// Destructor. + ~Routing_Slip_Queue (); + + /** + * \brief Add a routing slip to the tail of the queue and dispatch if necessary. + */ + void add (const Routing_Slip_Ptr & routing_slip); + /** + * \brief A call back to indicate that processing is complete for a previously-queued + * Routing_Slip. + */ + void complete (); + + /** + * /brief Adjust the "allowed" value on-the-fly (not recommended, but it works.) + */ + void set_allowed (size_t allowed); + + private: + void dispatch (Guard & guard); + bool dispatch_one (Guard & guard); + + private: + Routing_Slip_Queue (const Routing_Slip_Queue & rhs); + Routing_Slip_Queue & operator = (const Routing_Slip_Queue & rhs); + private: + // configuration setting + size_t allowed_; + /// Protection for internal information + TAO_SYNCH_MUTEX internals_; + size_t active_; + Queue queue_; + + }; +} // namespace + +#if defined (__ACE_INLINE__) +#include "Routing_Slip_Queue.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/post.h" +#endif /* TAO_NOTIFY_ROUTING_SLIP_QUEUE_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.cpp b/TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.cpp new file mode 100644 index 00000000000..edbb3518baf --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.cpp @@ -0,0 +1,46 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** +* @file Save_Persist_Worker_T.h +* +* $Id$ +* +* @author Jonathan Pollack <pollack_j@ociweb.com> +*/ +//============================================================================= + +#ifndef SAVE_PERSIST_WORKER_CPP +#define SAVE_PERSIST_WORKER_CPP + +#include "orbsvcs/ESF/ESF_Worker.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace TAO_NOTIFY +{ + template<class TOPOOBJ> + Save_Persist_Worker<TOPOOBJ>::Save_Persist_Worker( + Topology_Saver& saver, + bool want_all_children) + : saver_(saver) + , want_all_children_ (want_all_children) + { + } + + template<class TOPOOBJ> + void + Save_Persist_Worker<TOPOOBJ>::work (TOPOOBJ* o ACE_ENV_ARG_DECL) + { + ACE_ASSERT(o != 0); + if (this->want_all_children_ || o->is_changed ()) + { + o->save_persistent (saver_ ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + } +} // namespace TAO_NOTIFY + +#endif /* SAVE_PERSIST_WORKER_CPP */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.h b/TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.h new file mode 100644 index 00000000000..adee13f8de4 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Save_Persist_Worker_T.h @@ -0,0 +1,58 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** +* \file Save_Persist_Worker_T.h +* +* $Id$ +* +* \author Jonathan Pollack <pollack_j@ociweb.com> +*/ +//============================================================================= + +#ifndef SAVE_PERSIST_WORKER_H +#define SAVE_PERSIST_WORKER_H +#include /**/ "ace/pre.h" + +#include "orbsvcs/ESF/ESF_Worker.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace TAO_NOTIFY +{ + /** + * \brief Iterate through children saving persistent topology information. + */ + template<class TOPOOBJ> + class Save_Persist_Worker : public TAO_ESF_Worker<TOPOOBJ> + { + public: + /** + * /brief Constructor + * /param saver the object that will save persistent information. + * /param want_all_children if true, unmodified children should be saved, too. + */ + Save_Persist_Worker(Topology_Saver& saver, bool want_all_children); + + // override virtual ESF_Worker method + virtual void work (TOPOOBJ* o ACE_ENV_ARG_DECL); + + private: + Topology_Saver& saver_; + bool want_all_children_; + }; +} // namespace TAO_NOTIFY + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "Save_Persist_Worker_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Save_Persist_Worker_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* SAVE_PERSIST_WORKER_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.cpp b/TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.cpp new file mode 100644 index 00000000000..bd6b1053245 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.cpp @@ -0,0 +1,233 @@ +// $Id$ + +#include "Standard_Event_Persistence.h" +#include "Persistent_File_Allocator.h" +#include "tao/debug.h" +#include "ace/Dynamic_Service.h" +#include "ace/OS_NS_strings.h" + +namespace TAO_NOTIFY +{ + +Standard_Event_Persistence::Standard_Event_Persistence () + : filename_ ("__PERSISTENT_EVENT__.DB") + , block_size_ (512) + , factory_ (0) +{ +} + +Standard_Event_Persistence::~Standard_Event_Persistence () +{ +} + +// get the current factory, creating it if necessary +Event_Persistence_Factory * +Standard_Event_Persistence::get_factory () +{ + //@@todo guard? ; doublecheck? + if (this->factory_ == 0) + { + ACE_NEW_NORETURN ( + this->factory_, + Standard_Event_Persistence_Factory () + ); + if (this->factory_ != 0) + { + if (!this->factory_->open (this->filename_.c_str ())) + { + this->factory_ = 0; + } + } + } + return this->factory_; +} + +// release the current factory so a new one can be created +void +Standard_Event_Persistence::reset () +{ + delete this->factory_; + this->factory_ = 0; +} + +int +Standard_Event_Persistence::init (int argc, ACE_TCHAR *argv[]) +{ + int result = 0; + bool verbose = false; + for (int narg = 0; narg < argc; ++narg) + { + ACE_TCHAR * av = argv[narg]; + if (ACE_OS::strcasecmp (av, "-v") == 0) + { + verbose = true; + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Standard_Event_Persistence: -verbose\n") + )); + } + else if (ACE_OS::strcasecmp (av, "-file_path") == 0 && narg + 1 < argc) + { + this->filename_ = argv[narg + 1]; + if (TAO_debug_level > 0 || verbose) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Standard_Event_Persistence: Setting -file_path: %s\n"), + this->filename_.c_str () + )); + } + narg += 1; + } + else if (ACE_OS::strcasecmp (av, "-block_size") == 0 && narg + 1 < argc) + { + this->block_size_ = ACE_OS::atoi(argv[narg + 1]); + if (TAO_debug_level > 0 || verbose) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Standard_Event_Persistence: Setting -block_size: %d\n"), + this->block_size_ + )); + } + narg += 1; + } + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Unknown parameter to Standard Event Persistence: %s\n"), + argv[narg] + )); + result = -1; + } + } + return result; +} + +int +Standard_Event_Persistence::fini () +{ + delete this->factory_; + this->factory_ = 0; + return 0; +} + +Standard_Event_Persistence_Factory::Standard_Event_Persistence_Factory () + : allocator_() + , root_(this) + , psb_(0) + , serial_number_(ROUTING_SLIP_ROOT_SERIAL_NUMBER + 1) + , is_reloading_ (false) +{ +} + +bool +Standard_Event_Persistence_Factory::open (const char * filename, + ACE_UINT32 block_size) +{ + bool result = false; + if (allocator_.open (filename, block_size)) + { + this->is_reloading_ = this->root_.load(ROUTING_SLIP_ROOT_BLOCK_NUMBER, ROUTING_SLIP_ROOT_SERIAL_NUMBER); + if (! this->is_reloading_) + { + ACE_ASSERT (this->psb_ == 0); +// this->psb_ = this->allocator_.allocate(); + this->root_.store_root(); + } + result = true; + } + return result; +} + +Standard_Event_Persistence_Factory::~Standard_Event_Persistence_Factory() +{ + if (TAO_debug_level > 0) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Standard_Event_Persistence_Factory::~Standard_Event_Persistence_Factory\n") + )); + } + this->root_.release_all (); + delete this->psb_; + this->psb_ = 0; + this->allocator_.shutdown(); +} + +Routing_Slip_Persistence_Manager* +Standard_Event_Persistence_Factory::create_routing_slip_persistence_manager( + Persistent_Callback* callback) +{ + Routing_Slip_Persistence_Manager* rspm = 0; + ACE_NEW_RETURN(rspm, Routing_Slip_Persistence_Manager(this), rspm); + rspm->set_callback(callback); + return rspm; +} + +Routing_Slip_Persistence_Manager * +Standard_Event_Persistence_Factory::first_reload_manager() +{ + Routing_Slip_Persistence_Manager * result = 0; + if (this->is_reloading_) + { + result = this->root_.load_next(); + } + return result; +} + +void +Standard_Event_Persistence_Factory::done_reloading( + Persistent_Storage_Block * next_psb, + ACE_UINT64 current_serial_number) +{ + ACE_ASSERT (this->psb_ == 0); + this->psb_ = next_psb; + this->serial_number_ = current_serial_number; + this->is_reloading_ = false; +} + +void +Standard_Event_Persistence_Factory::preallocate_next_record( + ACE_UINT64& current_serial_number, + Persistent_Storage_Block*& current_psb, + ACE_UINT64& next_serial_number, + ACE_UINT32& next_block_number) +{ + // return current serial number and + // a psb containing current record number + current_serial_number = this->serial_number_; + this->psb_->set_allocator_owns(false); // give up ownership + this->psb_->set_sync(); + current_psb = this->psb_; + this->get_preallocated_pointer (next_serial_number, next_block_number); +} + +void +Standard_Event_Persistence_Factory::get_preallocated_pointer( + ACE_UINT64& next_serial_number, + ACE_UINT32& next_block_number) +{ + ++this->serial_number_; + this->psb_ = this->allocator_.allocate(); + + next_serial_number = this->serial_number_; + next_block_number = this->psb_->block_number(); +} + +Persistent_File_Allocator* +Standard_Event_Persistence_Factory::allocator() +{ + return &this->allocator_; +} + +Routing_Slip_Persistence_Manager & +Standard_Event_Persistence_Factory::root() +{ + return this->root_; +} + +ACE_FACTORY_DECLARE (TAO_Notify, Standard_Event_Persistence) +ACE_FACTORY_DEFINE (TAO_Notify, Standard_Event_Persistence) + +} + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.h b/TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.h new file mode 100644 index 00000000000..3079d7c6765 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Standard_Event_Persistence.h @@ -0,0 +1,128 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * \file Event_Persistence_Factory.h + * + * $Id$ + * + * The standard implementation of Event_Persistence_Factory. + * + * \author Jonathan Pollack <pollack_j@ociweb.com> + */ +//============================================================================= + +#ifndef STANDARD_EVENT_PERSISTENCE_H +#define STANDARD_EVENT_PERSISTENCE_H +#include /**/ "ace/pre.h" +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "Event_Persistence_Strategy.h" +#include "Event_Persistence_Factory.h" +#include "Persistent_File_Allocator.h" +#include "Routing_Slip_Persistence_Manager.h" +#include <ace/SString.h> + +namespace TAO_NOTIFY +{ +static const ACE_UINT32 ROUTING_SLIP_ROOT_BLOCK_NUMBER = 0; +static const ACE_UINT64 ROUTING_SLIP_ROOT_SERIAL_NUMBER = 1; + +/// \brief Standard (i.e. default) implementation of Event_Persistence_Factory interface +class TAO_Notify_Export Standard_Event_Persistence_Factory : + public Event_Persistence_Factory +{ +public: + /// Constructor + Standard_Event_Persistence_Factory (); + /// Destructor + virtual ~Standard_Event_Persistence_Factory(); + + /// Open persistence file and initialize. + /// /param filename the fully qualified path/name of the file to contain + /// persistent information. + /// /param block_size the size of a physical block on the device containing + /// the file. + bool open (const char * filename, ACE_UINT32 block_size = 512); + + ////////////////////////////////////////////////////// + // Implement Event_Persistence_Factory virtual methods. + virtual Routing_Slip_Persistence_Manager* + create_routing_slip_persistence_manager(Persistent_Callback* callback); + + virtual Routing_Slip_Persistence_Manager * first_reload_manager(); + + /// reloading process complete. Where should the chain continue? + void done_reloading( + Persistent_Storage_Block * next_psb, + ACE_UINT64 current_serial_number); + + /// return current serial # and a psb containing current record# + /// allocate new serial # and record number, and return those, too. + void preallocate_next_record( + ACE_UINT64& current_serial_number, + Persistent_Storage_Block*& current_psb, + ACE_UINT64& next_serial_number, + ACE_UINT32& next_block_number); + + // return block pointer info for the + void get_preallocated_pointer( + ACE_UINT64& next_serial_number, + ACE_UINT32& next_block_number); + + /// Accessor for file allocator. + /// Intended for use only by the Routing Slip Persistence Manager + Persistent_File_Allocator* allocator(); + + /// Access root record. + /// Intended for use only by the Routing Slip Persistence Manager + Routing_Slip_Persistence_Manager & root(); + +public: + ACE_SYNCH_MUTEX lock; + +private: + Persistent_File_Allocator allocator_; + Routing_Slip_Persistence_Manager root_; + Persistent_Storage_Block* psb_; + ACE_UINT64 serial_number_; + bool is_reloading_; +}; + +/// \brief The standard implementation of the +/// Event_Persistence_Strategy interface. +class TAO_Notify_Export Standard_Event_Persistence : + public Event_Persistence_Strategy +{ +public : + /// Constructor. + Standard_Event_Persistence (); + /// Destructor. + virtual ~Standard_Event_Persistence (); + ///////////////////////////////////////////// + // Override Event_Persistent_Strategy methods + // Parse arguments and initialize. + virtual int init(int argc, ACE_TCHAR *argv[]); + // Prepare for shutdown + virtual int fini (); + + // get the current factory, creating it if necessary + virtual Event_Persistence_Factory * get_factory (); + + // release the current factory so a new one can be created + virtual void reset (); + +private: + ACE_CString filename_; // set via -file_path + ACE_UINT32 block_size_; // set via -block_size + Standard_Event_Persistence_Factory * factory_; +}; + +} + +#include /**/ "ace/post.h" +#endif /* STANDARD_EVENT_PERSISTENCE_H */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.cpp b/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.cpp index 12e343f11b7..8c06d5864ee 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.cpp @@ -7,6 +7,7 @@ #endif /* __ACE_INLINE__ */ ACE_RCSID(RT_Notify, TAO_Notify_StructuredPushSupplier, "$Id$") +#include "../Properties.h" TAO_Notify_StructuredPushSupplier::TAO_Notify_StructuredPushSupplier (TAO_Notify_ProxyConsumer* proxy) :TAO_Notify_Supplier (proxy) @@ -31,3 +32,24 @@ TAO_Notify_StructuredPushSupplier::release (void) delete this; //@@ inform factory } + +bool +TAO_Notify_StructuredPushSupplier::get_ior (ACE_CString & iorstr) const +{ + bool result = false; + CORBA::ORB_var orb = TAO_Notify_PROPERTIES::instance()->orb(); + ACE_DECLARE_NEW_CORBA_ENV; + ACE_TRY + { + CORBA::String_var ior = orb->object_to_string(this->push_supplier_.in() ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + iorstr = ACE_static_cast (const char *, ior.in ()); + result = true; + } + ACE_CATCHANY + { + ACE_ASSERT(0); + } + ACE_ENDTRY; + return result; +} diff --git a/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.h b/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.h index f2329db3542..ddfdcd23017 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.h +++ b/TAO/orbsvcs/orbsvcs/Notify/Structured/StructuredPushSupplier.h @@ -45,6 +45,9 @@ public: /// Release virtual void release (void); + /// Retrieve the ior of this peer + virtual bool get_ior (ACE_CString & iorstr) const; + protected: /// The Supplier CosNotifyComm::StructuredPushSupplier_var push_supplier_; diff --git a/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.cpp b/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.cpp index 37823207801..50f1e93c42b 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.cpp +++ b/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.cpp @@ -6,19 +6,23 @@ #include "SupplierAdmin.inl" #endif /* __ACE_INLINE__ */ -ACE_RCSID (RT_Notify, - TAO_Notify_SupplierAdmin, +ACE_RCSID (RT_Notify, + TAO_Notify_SupplierAdmin, "$Id$") #include "orbsvcs/ESF/ESF_Proxy_Collection.h" #include "Builder.h" -#include "Proxy.h" +#include "ProxyConsumer.h" #include "EventChannel.h" #include "Subscription_Change_Worker.h" #include "Find_Worker_T.h" #include "Seq_Worker_T.h" #include "Properties.h" +#include "tao/debug.h" +//#define DEBUG_LEVEL 9 +#define DEBUG_LEVEL TAO_debug_level + typedef TAO_Notify_Find_Worker_T<TAO_Notify_Proxy , CosNotifyChannelAdmin::ProxyConsumer , CosNotifyChannelAdmin::ProxyConsumer_ptr @@ -28,9 +32,16 @@ TAO_Notify_ProxyConsumer_Find_Worker; typedef TAO_Notify_Seq_Worker_T<TAO_Notify_Proxy> TAO_Notify_Proxy_Seq_Worker; TAO_Notify_SupplierAdmin::TAO_Notify_SupplierAdmin (void) + : TAO_Notify_Admin () { } +const char * +TAO_Notify_SupplierAdmin::get_admin_type_name () const +{ + return "supplier_admin"; +} + TAO_Notify_SupplierAdmin::~TAO_Notify_SupplierAdmin () { } @@ -81,6 +92,65 @@ TAO_Notify_SupplierAdmin::destroy (ACE_ENV_SINGLE_ARG_DECL) ACE_CHECK; } +TAO_NOTIFY::Topology_Object* +TAO_Notify_SupplierAdmin::load_child (const ACE_CString &type, + CORBA::Long id, const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL) +{ + TAO_NOTIFY::Topology_Object* result = this; + if (type == "proxy_push_consumer") + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Admin reload proxy %d\n") + , ACE_static_cast (int, id) + )); + result = this->load_proxy(id, CosNotifyChannelAdmin::ANY_EVENT, attrs ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } + else if (type == "structured_proxy_push_consumer") + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Admin reload proxy %d\n") + , ACE_static_cast (int, id) + )); + result = this->load_proxy(id, CosNotifyChannelAdmin::STRUCTURED_EVENT, attrs ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } + else if (type == "sequence_proxy_push_consumer") + { + if (DEBUG_LEVEL) ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Admin reload proxy %d\n") + , ACE_static_cast (int, id) + )); + result = this->load_proxy(id, CosNotifyChannelAdmin::SEQUENCE_EVENT, attrs ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } + else + { + result = TAO_Notify_Admin::load_child (type, id, attrs ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + } + return result; +} + +TAO_NOTIFY::Topology_Object* +TAO_Notify_SupplierAdmin::load_proxy ( + CORBA::Long id, + CosNotifyChannelAdmin::ClientType ctype, + const TAO_NOTIFY::NVPList& attrs ACE_ENV_ARG_DECL) +{ + TAO_Notify_Builder* bld = TAO_Notify_PROPERTIES::instance()->builder(); + TAO_Notify_ProxyConsumer * proxy = + bld->build_proxy (this + , ctype + , id + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + ACE_ASSERT(proxy != 0); + proxy->load_attrs (attrs); + return proxy; +} + + void TAO_Notify_SupplierAdmin::set_qos (const CosNotification::QoSProperties & qos ACE_ENV_ARG_DECL) ACE_THROW_SPEC (( @@ -112,11 +182,16 @@ TAO_Notify_SupplierAdmin::obtain_notification_push_consumer (CosNotifyChannelAdm { CosNotification::QoSProperties initial_qos; - return TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this + CosNotifyChannelAdmin::ProxyConsumer_var proxy = + TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this , ctype , proxy_id , initial_qos ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (proxy._retn ()); + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (proxy._retn ()); + return proxy._retn (); } CosNotifyChannelAdmin::ProxyConsumer_ptr @@ -131,11 +206,16 @@ TAO_Notify_SupplierAdmin::obtain_notification_push_consumer_with_qos (CosNotifyC , CosNotification::UnsupportedQoS )) { - return TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this + CosNotifyChannelAdmin::ProxyConsumer_var proxy = + TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this , ctype , proxy_id, initial_qos ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (proxy._retn ()); + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (proxy._retn ()); + return proxy._retn (); } @@ -145,7 +225,12 @@ TAO_Notify_SupplierAdmin::obtain_push_consumer (ACE_ENV_SINGLE_ARG_DECL) CORBA::SystemException )) { - return TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this ACE_ENV_ARG_PARAMETER); + CosEventChannelAdmin::ProxyPushConsumer_var proxy = + TAO_Notify_PROPERTIES::instance()->builder()->build_proxy (this ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (proxy._retn ()); + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (proxy._retn ()); + return proxy._retn (); } CosNotifyChannelAdmin::AdminID @@ -231,7 +316,12 @@ TAO_Notify_SupplierAdmin::add_filter (CosNotifyFilter::Filter_ptr new_filter ACE CORBA::SystemException )) { - return this->filter_admin_.add_filter (new_filter ACE_ENV_ARG_PARAMETER); + CosNotifyFilter::FilterID fid = + this->filter_admin_.add_filter (new_filter ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (fid); + this->self_change (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (fid); + return fid; } void diff --git a/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.h b/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.h index bb1233eeae0..020a2b817a1 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.h +++ b/TAO/orbsvcs/orbsvcs/Notify/SupplierAdmin.h @@ -37,8 +37,8 @@ * @brief Implementation of CosNotifyChannelAdmin::SupplierAdmin * */ -class TAO_Notify_Serv_Export TAO_Notify_SupplierAdmin - : public virtual POA_NotifyExt::SupplierAdmin, +class TAO_Notify_Serv_Export TAO_Notify_SupplierAdmin + : public virtual POA_NotifyExt::SupplierAdmin, public virtual TAO_Notify_Admin { public: @@ -58,8 +58,22 @@ public: /// Release virtual void release (void); + virtual const char * get_admin_type_name () const; + + virtual TAO_NOTIFY::Topology_Object* load_child ( + const ACE_CString &type, + CORBA::Long id, + const TAO_NOTIFY::NVPList& attrs + ACE_ENV_ARG_DECL); + protected: + TAO_NOTIFY::Topology_Object *load_proxy ( + CORBA::Long id, + CosNotifyChannelAdmin::ClientType ctype, + const TAO_NOTIFY::NVPList& attrs + ACE_ENV_ARG_DECL); + /// = NotifyExt::SupplierAdmin methods CosNotifyChannelAdmin::ProxyConsumer_ptr obtain_notification_push_consumer_with_qos ( @@ -103,7 +117,7 @@ protected: ACE_THROW_SPEC ((CORBA::SystemException, CosNotifyChannelAdmin::ProxyNotFound)); - virtual ::CosNotifyChannelAdmin::ProxyConsumer_ptr + virtual ::CosNotifyChannelAdmin::ProxyConsumer_ptr obtain_notification_pull_consumer ( CosNotifyChannelAdmin::ClientType ctype, CosNotifyChannelAdmin::ProxyID_out proxy_id @@ -112,7 +126,7 @@ protected: ACE_THROW_SPEC ((CORBA::SystemException, CosNotifyChannelAdmin::AdminLimitExceeded)); - virtual ::CosNotifyChannelAdmin::ProxyConsumer_ptr + virtual ::CosNotifyChannelAdmin::ProxyConsumer_ptr obtain_notification_push_consumer ( CosNotifyChannelAdmin::ClientType ctype, CosNotifyChannelAdmin::ProxyID_out proxy_id @@ -127,7 +141,7 @@ protected: virtual ::CosNotification::QoSProperties* get_qos (ACE_ENV_SINGLE_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException)); - virtual void set_qos (const CosNotification::QoSProperties& qos + virtual void set_qos (const CosNotification::QoSProperties& qos ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, CosNotification::UnsupportedQoS)); @@ -160,7 +174,7 @@ protected: CosNotifyFilter::FilterNotFound)); virtual ::CosNotifyFilter::Filter_ptr get_filter ( - CosNotifyFilter::FilterID filter + CosNotifyFilter::FilterID filter ACE_ENV_ARG_DECL ) ACE_THROW_SPEC ((CORBA::SystemException, diff --git a/TAO/orbsvcs/orbsvcs/Notify/Topology_Factory.h b/TAO/orbsvcs/orbsvcs/Notify/Topology_Factory.h new file mode 100644 index 00000000000..7526159f717 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Topology_Factory.h @@ -0,0 +1,46 @@ +/** + * @file Topology_Factory.h + * + * $Id$ + * + * @author Dale Wilson <wilson_d@ociweb.com> + * + * + */ +#ifndef TAO_NOTIFY_TOPOLOGY_FACTORY_H +#define TAO_NOTIFY_TOPOLOGY_FACTORY_H +#include /**/ "ace/pre.h" + +#include "notify_serv_export.h" + +#include "ace/Service_Object.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace TAO_NOTIFY +{ + class Topology_Saver; + class Topology_Loader; + + /** + * @brief Service Object to allow dynamic control of the loaded saver factory. + * + */ + class TAO_Notify_Serv_Export Topology_Factory : public ACE_Service_Object + { + public: + /// Create a Saver. + /// \return a pointer to a Topology_Saver which must be deleted + /// by the caller. + virtual Topology_Saver* create_saver () = 0; + /// Create a Loader + /// \return a pointer to a Topology_Loader which must be deleted + /// by the caller. + virtual Topology_Loader* create_loader () = 0; + }; +} + +#include /**/ "ace/post.h" +#endif diff --git a/TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.cpp b/TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.cpp new file mode 100644 index 00000000000..4eb9e308531 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.cpp @@ -0,0 +1,16 @@ +// $Id$ + +#include "Topology_Loader.h" + +TAO_NOTIFY::Topology_Loader::Topology_Loader () +{ +} + +TAO_NOTIFY::Topology_Loader::~Topology_Loader () +{ +} + +void +TAO_NOTIFY::Topology_Loader::close (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) +{ +} diff --git a/TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.h b/TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.h new file mode 100644 index 00000000000..a06494c80a1 --- /dev/null +++ b/TAO/orbsvcs/orbsvcs/Notify/Topology_Loader.h @@ -0,0 +1,73 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Topology_Loader.h + * + * $Id$ + * + * @author Jonathan Pollack <pollack_j@ociweb.com> + */ +//============================================================================= + +#ifndef TOPOLOGY_LOADER_H +#define TOPOLOGY_LOADER_H +#include "ace/pre.h" + +#include "ace/config-all.h" + +#include "tao/corba.h" +#include "notify_serv_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +namespace TAO_NOTIFY +{ + +/// A forward declaration. +class Topology_Object; + +/** + * \brief An interface for an object that loads Persistent Topology Information. + * + * A persistent store must provide an implemention this interface. + * + */ +class TAO_Notify_Serv_Export Topology_Loader +{ +public: + /// The constructor. + Topology_Loader (); + + /// The destructor. + virtual ~Topology_Loader (); + + /** \brief Begin the restore process. + * + * Call this function to start the reload of data from a persistent store. + * When the Topology_Loader detects a child object, it should + * call the load_child method of the object passed in, then do the same + * loading process on the returned object. + */ + virtual void load (Topology_Object *root ACE_ENV_ARG_DECL) = 0; + + /** + * \brief Close the loader after loading is complete. + * + * This is not pure virtual because some loaders may not need to be closed. + * The default implementation does nothing. + * + * There should be a corresponding open, but the signature may + * vary based on the type of loader, so we can't include it in the + * interface. + */ + virtual void close (ACE_ENV_SINGLE_ARG_DECL); +}; + +} // namespace TAO_NOTIFY + +#include /**/ "ace/post.h" + +#endif /* TOPOLOGY_LOADER */ diff --git a/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.h b/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.h index de7adc1c23b..19654b3db7a 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.h +++ b/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.h @@ -123,7 +123,7 @@ namespace TAO_NOTIFY /// the get_id returns the same thing as id -- we just need someone /// to find it for us. virtual TAO_Notify_Object_Id get_id () const; - + /// \brief Get the path of id's from the root to this object. void get_id_path (IdVec & id_path) const; diff --git a/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.inl b/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.inl index 1c12c7df671..6c2c3b88396 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.inl +++ b/TAO/orbsvcs/orbsvcs/Notify/Topology_Object.inl @@ -2,7 +2,7 @@ namespace TAO_NOTIFY { ACE_INLINE - bool + bool Topology_Object::is_changed () const { return this->self_changed_ | this->children_changed_; diff --git a/TAO/orbsvcs/orbsvcs/Notify/XML_Saver.h b/TAO/orbsvcs/orbsvcs/Notify/XML_Saver.h index 1d5beff9e5e..e1956637a95 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/XML_Saver.h +++ b/TAO/orbsvcs/orbsvcs/Notify/XML_Saver.h @@ -37,12 +37,12 @@ public: XML_Saver (bool timestamp = true); virtual ~XML_Saver (); - + /// Open the output file. /// \param file_name the fully qualified file name /// \return true if successful bool open (const ACE_CString & file_name, size_t backup_count); - + ////////////////////////////////// // Override Topology_Saver methods // see Topology_Saver.h for doc diff --git a/TAO/orbsvcs/orbsvcs/Notify/XML_Topology_Factory.h b/TAO/orbsvcs/orbsvcs/Notify/XML_Topology_Factory.h index e063acdbc42..97a14512cfa 100644 --- a/TAO/orbsvcs/orbsvcs/Notify/XML_Topology_Factory.h +++ b/TAO/orbsvcs/orbsvcs/Notify/XML_Topology_Factory.h @@ -63,7 +63,7 @@ namespace TAO_NOTIFY // documented in ace/Shared_Object.h virtual int init (int argc, ACE_TCHAR *argv[]); virtual int fini (); - + private: ACE_CString save_base_path_; ACE_CString load_base_path_; diff --git a/TAO/orbsvcs/orbsvcs/NotifyExt.idl b/TAO/orbsvcs/orbsvcs/NotifyExt.idl index 7c94e9bcb26..5e0d9ca9b69 100644 --- a/TAO/orbsvcs/orbsvcs/NotifyExt.idl +++ b/TAO/orbsvcs/orbsvcs/NotifyExt.idl @@ -83,12 +83,55 @@ module NotifyExt unsigned long max_request_buffer_size; }; - /* - * Extend the EventChannelFactory to have a shutdown method. + /** + * \brief An interface which gets registered with a ReconnectionRegistry. + * + * A supplier or consumer must implement this interface in order to + * allow the Notification Service to attempt to reconnect to it after + * a failure. The supplier or consumer must register its instance of + * this interface with the ReconnectionRegistry. + */ + interface ReconnectionCallback + { + /// Perform operations to reconnect to the Notification Service + /// after a failure. + void reconnect (in Object new_connection); + + /// Check to see if the ReconnectionCallba ck is alive + boolean is_alive (); + }; + + /** + * \brief An interface that handles registration of suppliers and consumers. + * + * This registry should be implemented by an EventChannelFactory and + * will call the appropriate reconnect methods for all ReconnectionCallback + * objects registered with it. + */ + interface ReconnectionRegistry + { + typedef long ReconnectionID; + ReconnectionID register_callback(in ReconnectionCallback reconection); + + void unregister_callback (in ReconnectionID id); + + /// Check to see if the ReconnectionRegistry is alive + boolean is_alive (); + }; + + /** + * Extend the EventChannelFactory to have a shutdown method + * and a Reconnection Registry */ - interface EventChannelFactory : CosNotifyChannelAdmin::EventChannelFactory + interface EventChannelFactory + : CosNotifyChannelAdmin::EventChannelFactory + , ReconnectionRegistry { void destroy (); + /// save topology: for diagnostic and testing purposes + /// Normal topology save is automatic when connectivity persistence + /// is configured. + void save_topology(); }; interface ConsumerAdmin : CosNotifyChannelAdmin::ConsumerAdmin diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/PlugTop.mpc b/TAO/orbsvcs/tests/Notify/PluggableTopology/PlugTop.mpc new file mode 100644 index 00000000000..dda1bb794af --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/PlugTop.mpc @@ -0,0 +1,19 @@ +project(*lib): orbsvcslib, notify_serv { + requires += exceptions; + sharedname = NotifyPlugTop + dynamicflags = PLUGTOP_BUILD_DLL + source_files { + Test_Saver.cpp + Test_Topology_Factory.cpp + } +} + +project : orbsvcsexe, notify_serv { + requires += exceptions; + after += *lib + source_files { + main.cpp + } + header_files { + } +} diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.cpp b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.cpp new file mode 100644 index 00000000000..567979e64c2 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.cpp @@ -0,0 +1,37 @@ +// $Id$ + +#include "Test_Saver.h" + +#include <ace/streams.h> + +Test_Saver::Test_Saver() +{ +} + +bool +Test_Saver::begin_object(CORBA::Long id, + const ACE_CString &type, + const TAO_NOTIFY::NVPList& attrs, + bool changed + ACE_ENV_ARG_DECL_NOT_USED) +{ + cout << "Test_Saver::begin_object type=\"" << type << "\" " + << " id=" << id + << " changed=\"" << changed << "\""; + for (size_t idx = 0; idx < attrs.size(); idx++) + { + cout << " " << attrs[idx].name << "=\"" << attrs[idx].value << "\""; + } + cout << endl; + return true; +} + +void +Test_Saver::end_object (CORBA::Long id, + const ACE_CString &type ACE_ENV_ARG_DECL_NOT_USED) +{ + cout << "Test_Saver::end_object type=\"" << type << "\"" + << " id=" << id + << endl; +} + diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.h b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.h new file mode 100644 index 00000000000..ce95cb0781c --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Saver.h @@ -0,0 +1,39 @@ +/* -*- C++ -*- */ +/** + * $Id$ + */ + +#ifndef TEST_SAVER_H +#define TEST_SAVER_H +#include /**/ "ace/pre.h" + +#include "plugtop_export.h" + +#include "orbsvcs/Notify/Topology_Saver.h" + +#include "tao/corba.h" +#include "ace/streams.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +class PLUGTOP_Export Test_Saver : public TAO_NOTIFY::Topology_Saver +{ +public: + Test_Saver(); + + virtual bool begin_object (CORBA::Long id, + const ACE_CString &type, + const TAO_NOTIFY::NVPList& attrs, + bool changed + ACE_ENV_ARG_DECL); + + virtual void end_object (CORBA::Long id, + const ACE_CString &type + ACE_ENV_ARG_DECL); +}; + + +#include /**/ "ace/post.h" +#endif /* TEST_SAVER_H */ diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.cpp b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.cpp new file mode 100644 index 00000000000..fdab5be129c --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.cpp @@ -0,0 +1,26 @@ +// $Id$ + +#include "Test_Topology_Factory.h" +#include "Test_Saver.h" + +Test_Topology_Factory::Test_Topology_Factory() +{ +} + +TAO_NOTIFY::Topology_Saver* +Test_Topology_Factory::create_saver () +{ + TAO_NOTIFY::Topology_Saver *saver = 0; + ACE_NEW_RETURN (saver, Test_Saver, 0); + return saver; +} + +//virtual +TAO_NOTIFY::Topology_Loader* +Test_Topology_Factory::create_loader () +{ + return 0; +} + + +ACE_FACTORY_DEFINE (PLUGTOP, Test_Topology_Factory) diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.h b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.h new file mode 100644 index 00000000000..6b76b1a2205 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/Test_Topology_Factory.h @@ -0,0 +1,31 @@ +/* -*- C++ -*- */ +//$Id$ + +#ifndef TEST_TOPOLOGY_FACTORY_H +#define TEST_TOPOLOGY_FACTORY_H +#include /**/ "ace/pre.h" + +#include "plugtop_export.h" + +#include "orbsvcs/Notify/Topology_Factory.h" + +#include "tao/corba.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +class PLUGTOP_Export Test_Topology_Factory : public TAO_NOTIFY::Topology_Factory +{ +public: + Test_Topology_Factory (); + ///////////////////////////////////////////////// + // override virtual methods from Topology_Factory + virtual TAO_NOTIFY::Topology_Saver* create_saver (); + virtual TAO_NOTIFY::Topology_Loader* create_loader (); +}; + +ACE_FACTORY_DECLARE (PLUGTOP, Test_Topology_Factory) + +#include /**/ "ace/post.h" +#endif /* TEST_TOPOLOGY_FACTORY_H */ diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/main.cpp b/TAO/orbsvcs/tests/Notify/PluggableTopology/main.cpp new file mode 100644 index 00000000000..786728187fa --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/main.cpp @@ -0,0 +1,109 @@ +/** + * $Id$ + */ + +#include <orbsvcs/CosNotifyChannelAdminC.h> +//#include <orbsvcs/CosNotifyCommS.h> +//#include <orbsvcs/CosNotificationS.h> +#include <tao/TimeBaseC.h> + +#include <ace/ARGV.h> +#include <ace/OS_NS_stdio.h> + +using namespace CORBA; +namespace CNCA = CosNotifyChannelAdmin; +namespace CN = CosNotification; +namespace CNC = CosNotifyComm; + +const char* NOTIFY_IOR = "corbaloc::localhost:9050/NotifyEventChannelFactory"; + +ORB_var orb; +CNCA::EventChannelFactory_var ecf; + +namespace { + void init_qos_props(CN::QoSProperties& qos, bool topology_persist) { + qos.length(13); + ULong i = 0; + qos[i].name = "EventReliability"; + qos[i++].value <<= CN::BestEffort; + if (topology_persist) { + qos[i].name = "ConnectionReliability"; + qos[i++].value <<= CN::Persistent; + } + else + { + qos[i].name = "ConnectionReliability"; + qos[i++].value <<= CN::BestEffort; + } + qos[i].name = "Priority"; + qos[i++].value <<= (Short) 1234; + qos[i].name = "Timeout"; + qos[i++].value <<= (TimeBase::TimeT) 55555; + qos[i].name = "MaximumBatchSize"; + qos[i++].value <<= (Long) 200; + qos[i].name = "PacingInterval"; + qos[i++].value <<= (TimeBase::TimeT) 42000; + qos[i].name = "StopTimeSupported"; + qos[i++].value <<= Any::from_boolean(0); + qos.length(i); + } + void init_admin_props(CN::AdminProperties& admin) { + admin.length(13); + ULong i = 0; + admin[i].name = "MaxQueueLength"; + admin[i++].value <<= (Long) 200; + admin[i].name = "MaxConsumers"; + admin[i++].value <<= (Long) 2; + admin[i].name = "MaxSuppliers"; + admin[i++].value <<= (Long) 1; + admin[i].name = "RejectNewEvents"; + admin[i++].value <<= Any::from_boolean(1); + } + void setUp() + { + ACE_ARGV av; + int ac = 0; + orb = ORB_init(ac, av.argv()); + ACE_ASSERT(! is_nil(orb.in())); + Object_var obj = orb->string_to_object(NOTIFY_IOR); + ACE_ASSERT(! is_nil(obj.in())); + ecf = CNCA::EventChannelFactory::_narrow(obj.in()); + ACE_ASSERT(! is_nil(ecf.in())); + } + + void tearDown() + { + ecf = CNCA::EventChannelFactory::_nil(); + orb->destroy(); + orb = ORB::_nil(); + } +} + + +int main(int, char**) +{ + try + { + setUp(); + + CN::QoSProperties qos; + CN::AdminProperties admin; + init_qos_props(qos, true); + init_admin_props(admin); + + CNCA::ChannelID ecid; + CNCA::EventChannel_var ec = ecf->create_channel(qos, admin, ecid); + + printf("Created channel id=\"%ld\"\n", static_cast<long>(ecid)); + + tearDown(); + + return 0; + } + catch (Exception& e) + { + ACE_OS::fputs(e._name (), stderr); + ACE_OS::fputs("\n", stderr); + } + return 1; +} diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_export.h b/TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_export.h new file mode 100644 index 00000000000..fe7fbfbee28 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_export.h @@ -0,0 +1,40 @@ + +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl +// ------------------------------ +#ifndef PLUGTOP_EXPORT_H +#define PLUGTOP_EXPORT_H + +#include "ace/config-all.h" + +#if defined (TAO_AS_STATIC_LIBS) +# if !defined (PLUGTOP_HAS_DLL) +# define PLUGTOP_HAS_DLL 0 +# endif /* ! PLUGTOP_HAS_DLL */ +#else +# if !defined (PLUGTOP_HAS_DLL) +# define PLUGTOP_HAS_DLL 1 +# endif /* ! PLUGTOP_HAS_DLL */ +#endif + +#if defined (PLUGTOP_HAS_DLL) && (PLUGTOP_HAS_DLL == 1) +# if defined (PLUGTOP_BUILD_DLL) +# define PLUGTOP_Export ACE_Proper_Export_Flag +# define PLUGTOP_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define PLUGTOP_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* PLUGTOP_BUILD_DLL */ +# define PLUGTOP_Export ACE_Proper_Import_Flag +# define PLUGTOP_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define PLUGTOP_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* PLUGTOP_BUILD_DLL */ +#else /* PLUGTOP_HAS_DLL == 1 */ +# define PLUGTOP_Export +# define PLUGTOP_SINGLETON_DECLARATION(T) +# define PLUGTOP_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* PLUGTOP_HAS_DLL == 1 */ + +#endif /* PLUGTOP_EXPORT_H */ + +// End of auto generated file. diff --git a/TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_ns.conf b/TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_ns.conf new file mode 100644 index 00000000000..63b5faf531b --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/PluggableTopology/plugtop_ns.conf @@ -0,0 +1,3 @@ + +dynamic TopologyFactory Service_Object * NotifyPlugTop:_make_Test_Topology_Factory() "" +#dynamic TopologyFactory Service_Object * TAO_CosNotification:_make_XML_Topology_Factory() ""
\ No newline at end of file diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.cpp b/TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.cpp new file mode 100644 index 00000000000..d2837a547b4 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.cpp @@ -0,0 +1,1878 @@ +//$Id$ + +#include "Consumer.h" +#include "tao/debug.h" +#include "tao/PortableServer/PortableServerC.h" +#include <tao/TimeBaseC.h> +#include <ace/OS_NS_strings.h> +#include <ace/OS_NS_stdio.h> +#include <tao/Any.h> + +ACE_RCSID (Notify_Tests, Consumer_Main, "$Id$") + +static const char NOTIFY_FACTORY_NAME[] = "NotifyEventChannelFactory"; +static const char NAMING_SERVICE_NAME[] = "NameService"; + +static const size_t minus_one = ACE_static_cast (size_t, -1); + +/////////////////////////// +// StructuredPushConsumer_i + +StructuredPushConsumer_i::StructuredPushConsumer_i () + : verbose_ (false) + , received_ (0) + , expect_ (10) + , fail_ (0) + , may_discard_ (0) + , serial_number_ (0) + , exceptions_thrown_ (0) + , problem_ (false) + , connected_ (false) +{ +} + +size_t +StructuredPushConsumer_i::received () const +{ + return this->received_; +} + +bool +StructuredPushConsumer_i::has_problem () const +{ + return this->problem_; +} + +void +StructuredPushConsumer_i::set_connected (bool flag) +{ + this->connected_ = flag; +} + +bool +StructuredPushConsumer_i::is_connected () const +{ + return this->connected_; +} + +void +StructuredPushConsumer_i::set_expectations (size_t expected, size_t fail, size_t serial_number, bool verbose) +{ + this->expect_ = expected; + this->fail_ = fail; + this->serial_number_ = serial_number; + this->verbose_ = verbose; +} + +void +StructuredPushConsumer_i::offer_change ( + const CosNotification::EventTypeSeq & added, + const CosNotification::EventTypeSeq & removed + ACE_ENV_ARG_DECL_NOT_USED + ) + ACE_THROW_SPEC (( + CORBA::SystemException, + CosNotifyComm::InvalidEventType)) +{ + ACE_UNUSED_ARG (added); + ACE_UNUSED_ARG (removed); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) StructuredPushConsumer offered change \n") + )); +} + +void +StructuredPushConsumer_i::check_serial_number (CORBA::ULong seq) +{ + if (this->serial_number_ == minus_one) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Structured Consumer received event %d.\n"), + ACE_static_cast (int, seq) + )); + } + } + else + { + if (seq == this->serial_number_) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Structured Consumer received correct event %d.\n"), + ACE_static_cast (int, seq) + )); + } + } + else if ((seq - this->serial_number_) <= this->may_discard_) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Structured Consumer: service received event %d; Notify discarded %d*.\n"), + ACE_static_cast (int, seq), + ACE_static_cast (int, this->serial_number_) + )); + } + this->received_ += seq - this->serial_number_; + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Structured Consumer received notifications out of sequence. Expecting %d received %d.\n"), + ACE_static_cast (int, this->serial_number_), + ACE_static_cast (int, seq) + )); + } + this->serial_number_ = seq + 1; + } + may_discard_ = 0; +} + + +void +StructuredPushConsumer_i::push_structured_event ( + const CosNotification::StructuredEvent & notification + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException, + CosEventComm::Disconnected)) +{ + this->received_ += 1; + if (this->received_ == this->expect_ + 1) + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Structured Consumer received more than the %d events that were expected.\n"), + this->expect_ + )); + } + if (this->fail_ != 0 && ((this->received_ + this->exceptions_thrown_) % this->fail_) == 0) + { + this->received_ -= 1; + this->exceptions_thrown_ += 1; + this->may_discard_ = 1; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Structured Consumer failing at event # %d.\n"), + ACE_static_cast (int, this->received_) + )); + ACE_THROW (CORBA::UNKNOWN()); + ACE_CHECK; + } + if (notification.filterable_data.length () > 0) + { + if (0 == ACE_OS::strcmp (notification.filterable_data[0].name, "serial_number")) + { + const CORBA::Any & data = notification.filterable_data[0].value; + + CORBA::ULong seq = 0; + if (data >>= seq) + { + check_serial_number (seq); + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Structured Consumer received unexpected data type for serial_number.\n") + )); + } + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Structured Consumer received wrong filterable data name.%s. Expecting serial_number\n"), + ACE_static_cast (const char *, notification.filterable_data[0].name) + )); + } + } + else if (0 == ACE_OS::strcmp (notification.header.fixed_header.event_type.type_name, "%ANY") + && 0 == strcmp (notification.header.fixed_header.event_type.domain_name, "")) + { + const CORBA::Any * any; + if (notification.remainder_of_body >>= any) + { + // this is a wrapped "Any" + CORBA::ULong seq = 0; + if ((*any) >>= seq) + { + check_serial_number (seq); + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Structured Consumer received Any with unknown data type\n") + )); + } + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Structured Consumer received remainder_of_body with unknown data type\n") + )); + } + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Structured Consumer: no filterable data. \n") + )); + } + this->may_discard_ = 0; +} + +void +StructuredPushConsumer_i::disconnect_structured_push_consumer ( + ACE_ENV_SINGLE_ARG_DECL_NOT_USED + ) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) StructuredPushConsumer received disconnect\n") + )); +} + +/////////////////////////// +// SequencePushConsumer_i + +SequencePushConsumer_i::SequencePushConsumer_i () + : verbose_ (false) + , received_ (0) + , expect_ (10) + , fail_ (0) + , may_discard_ (0) + , serial_number_ (0) + , exceptions_thrown_ (0) + , problem_ (false) + , connected_ (false) +{ +} + +size_t +SequencePushConsumer_i::received () const +{ + return this->received_; +} + +bool +SequencePushConsumer_i::has_problem () const +{ + return this->problem_; +} + +void +SequencePushConsumer_i::set_connected (bool flag) +{ + this->connected_ = flag; +} + +bool +SequencePushConsumer_i::is_connected () const +{ + return this->connected_; +} + +void +SequencePushConsumer_i::set_expectations (size_t expected, size_t fail,size_t serial_number, bool verbose) +{ + this->expect_ = expected; + this->fail_ = fail; + this->serial_number_ = serial_number; + this->verbose_ = verbose; +} + +void +SequencePushConsumer_i::offer_change ( + const CosNotification::EventTypeSeq & added, + const CosNotification::EventTypeSeq & removed + ACE_ENV_ARG_DECL_NOT_USED + ) + ACE_THROW_SPEC (( + CORBA::SystemException, + CosNotifyComm::InvalidEventType)) +{ + ACE_UNUSED_ARG (added); + ACE_UNUSED_ARG (removed); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) SequencePushConsumer offered subscription change\n") + )); +} + +void +SequencePushConsumer_i::check_serial_number (CORBA::ULong seq) +{ + if (this->serial_number_ == minus_one) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Sequence Consumer received event %d.\n"), + ACE_static_cast (int, seq) + )); + } + } + else + { + if (seq == this->serial_number_) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Sequence Consumer received correct event %d.\n"), + ACE_static_cast (int, seq) + )); + } + } + else if ((seq - this->serial_number_) <= this->may_discard_) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Sequence Consumer: service received event %d; Notify discarded %d*.\n"), + ACE_static_cast (int, seq), + ACE_static_cast (int, this->serial_number_) + )); + } + this->received_ += seq - this->serial_number_; + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Sequence Consumer received notifications out of sequence. Expecting %d received %d.\n"), + ACE_static_cast (int, this->serial_number_), + ACE_static_cast (int, seq) + )); + } + this->serial_number_ = seq + 1; + } + may_discard_ = 0; +} + +void +SequencePushConsumer_i::push_structured_events ( + const CosNotification::EventBatch & notifications + ACE_ENV_ARG_DECL + ) + ACE_THROW_SPEC ((CORBA::SystemException, + CosEventComm::Disconnected)) +{ + size_t batch_size = notifications.length(); + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Sequence Consumer received batch of %d events.\n"), + ACE_static_cast (int, batch_size) + )); + } + for (size_t nevent = 0; nevent < batch_size; ++nevent) + { + this->received_ += 1; + if (this->received_ == this->expect_ + 1) + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Sequence Consumer received more than the %d events that were expected.\n"), + this->expect_ + )); + } + if (this->fail_ != 0 && ((this->received_ + this->exceptions_thrown_) % this->fail_) == 0) + { + this->received_ -= 1; + this->exceptions_thrown_ += 1; + this->may_discard_ = batch_size; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Sequence Consumer failing at event # %d. Expecting %d duplicates.\n"), + ACE_static_cast (int, this->received_), + ACE_static_cast (int, nevent + 1) + )); + ACE_THROW (CORBA::UNKNOWN()); + ACE_CHECK; + } + const CosNotification::StructuredEvent & notification = notifications[nevent]; + if (notification.filterable_data.length () > 0) + { + if (0 == ACE_OS::strcmp (notification.filterable_data[0].name, "serial_number")) + { + const CORBA::Any & data = notification.filterable_data[0].value; + + CORBA::ULong seq = 0; + if (data >>= seq) + { + check_serial_number (seq); + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Sequence Consumer received unexpected data type for serial_number.\n") + )); + } + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Sequence Consumer received wrong filterable data name.%s. Expecting serial_number\n"), + ACE_static_cast (const char *, notification.filterable_data[0].name) + )); + } + } + else if (0 == ACE_OS::strcmp (notification.header.fixed_header.event_type.type_name, "%ANY") + && 0 == strcmp (notification.header.fixed_header.event_type.domain_name, "")) + { + CORBA::ULong seq = 0; + if (notification.remainder_of_body >>= seq) + { + check_serial_number (seq); + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Sequence Consumer received Any with unknown data type\n") + )); + } + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Sequence Consumer received no filterable data\n") + )); + } + } +} + +void +SequencePushConsumer_i::disconnect_sequence_push_consumer ( + ACE_ENV_SINGLE_ARG_DECL_NOT_USED + ) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) SequencePushConsumer received disconnect\n") + )); +} + +/////////////////////////// +// AnyPushConsumer_i + +AnyPushConsumer_i::AnyPushConsumer_i () + : verbose_ (false) + , received_ (0) + , expect_ (10) + , fail_ (0) + , may_discard_ (0) + , serial_number_ (0) + , exceptions_thrown_ (0) + , problem_ (false) + , connected_ (false) +{ +} + +size_t +AnyPushConsumer_i::received () const +{ + return this->received_; +} + +bool +AnyPushConsumer_i::has_problem () const +{ + return this->problem_; +} + +void +AnyPushConsumer_i::set_connected (bool flag) +{ + this->connected_ = flag; +} + +bool +AnyPushConsumer_i::is_connected () const +{ + return this->connected_; +} + +void +AnyPushConsumer_i::set_expectations (size_t expected, size_t fail, size_t serial_number, bool verbose) +{ + this->expect_ = expected; + this->fail_ = fail; + this->serial_number_ = serial_number; + this->verbose_ = verbose; +} + +void +AnyPushConsumer_i::offer_change ( + const CosNotification::EventTypeSeq & added, + const CosNotification::EventTypeSeq & removed + ACE_ENV_ARG_DECL_NOT_USED + ) + ACE_THROW_SPEC (( + CORBA::SystemException, + CosNotifyComm::InvalidEventType)) +{ + ACE_UNUSED_ARG (added); + ACE_UNUSED_ARG (removed); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) SequencePushConsumer offered subscription change\n") + )); +} + +void +AnyPushConsumer_i::check_serial_number (CORBA::ULong seq) +{ + if (this->serial_number_ == minus_one) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Any Consumer received event %d.\n"), + ACE_static_cast (int, seq) + )); + } + } + else + { + if (seq == this->serial_number_) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Any Consumer received correct event %d.\n"), + ACE_static_cast (int, seq) + )); + } + } + else if ((seq - this->serial_number_) <= this->may_discard_) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Any Consumer: service received event %d; Notify discarded %d*.\n"), + ACE_static_cast (int, seq), + ACE_static_cast (int, this->serial_number_) + )); + } + this->received_ += seq - this->serial_number_; + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Any Consumer received notifications out of sequence. Expecting %d received %d.\n"), + ACE_static_cast (int, this->serial_number_), + ACE_static_cast (int, seq) + )); + } + this->serial_number_ = seq + 1; + } + may_discard_ = 0; +} + +void +AnyPushConsumer_i::push ( + const CORBA::Any & data + ACE_ENV_ARG_DECL + ) + ACE_THROW_SPEC ((CORBA::SystemException, + CosEventComm::Disconnected)) +{ + this->received_ += 1; + if (this->received_ == this->expect_ + 1) + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Any Consumer received more than the %d events that were expected.\n"), + this->expect_ + )); + } + if (this->fail_ != 0 && ((this->received_ + this->exceptions_thrown_) % this->fail_) == 0) + { + this->received_ -= 1; + this->exceptions_thrown_ += 1; + this->may_discard_ = 1; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Any Consumer failing at event # %d.\n"), + ACE_static_cast (int, this->received_) + )); + ACE_THROW (CORBA::UNKNOWN()); + ACE_CHECK; + } + CORBA::ULong seq = 0; + if (data >>= seq) + { + check_serial_number (seq); + } + else + { + const CosNotification::StructuredEvent * notification; + if (data >>= notification) + { + if (notification->filterable_data.length () > 0) + { + if (0 == ACE_OS::strcmp (notification->filterable_data[0].name, "serial_number")) + { + const CORBA::Any & data = notification->filterable_data[0].value; + + CORBA::ULong seq = 0; + if (data >>= seq) + { + check_serial_number (seq); + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Any Consumer received structured notification with unexpected data type for serial_number in structured event.\n") + )); + } + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Any Consumer received wrong filterable data name in structured event: %s. Expecting serial_number\n"), + ACE_static_cast (const char *, notification->filterable_data[0].name) + )); + } + } + else + { + this->problem_ = true; + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Any Consumer: no filterable data in structured event. \n") + )); + } + } + else + { + this->problem_ = true; + + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) Any Consumer received unexpected data type.\n") + )); + } + } +} + +void +AnyPushConsumer_i::disconnect_push_consumer ( + ACE_ENV_SINGLE_ARG_DECL_NOT_USED + ) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) AnyPushConsumer received disconnect\n") + )); +} + +///////////////////////// +// ReconnectionCallback_i + +ReconnectionCallback_i::ReconnectionCallback_i (Consumer_Main & consumer_main) + : consumer_main_ (consumer_main) + , id_is_valid_ (false) + , reconnect_count_ (0) +{ +} + +size_t +ReconnectionCallback_i::reconnect_count () const +{ + return this->reconnect_count_; +} + +void +ReconnectionCallback_i::reconnect ( + CORBA::Object_ptr reconnection + ACE_ENV_ARG_DECL + ) ACE_THROW_SPEC ((CORBA::SystemException)) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer received reconnection request\n") + )); + this->ecf_ = CosNotifyChannelAdmin::EventChannelFactory::_narrow (reconnection ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + if (!CORBA::is_nil (this->ecf_.in ())) + { + this->consumer_main_.reconnect (this->ecf_.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + this->reconnect_count_ += 1; + } + else + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer reconnection request failed: wrong object type\n") + )); + } +} + +CORBA::Boolean +ReconnectionCallback_i::is_alive (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + return CORBA::Boolean (1); +} + + +ReconnectionCallback_i::~ReconnectionCallback_i () +{ + // normally you would disconnect from registry here, but + // to simulate a failure, we exit without cleaning up + // if the fini method is not called. +} + + +void +ReconnectionCallback_i::fini (ACE_ENV_SINGLE_ARG_DECL) +{ + if (this->id_is_valid_) + { + NotifyExt::ReconnectionRegistry_var registry = + NotifyExt::ReconnectionRegistry::_narrow (this->ecf_.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + registry->unregister_callback (this->callback_id_ ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + this->id_is_valid_ = false; + } +} + +void +ReconnectionCallback_i::init ( + PortableServer::POA_ptr poa, + CosNotifyChannelAdmin::EventChannelFactory_ptr ecf + ACE_ENV_ARG_DECL) +{ + this->ecf_ = CosNotifyChannelAdmin::EventChannelFactory::_duplicate (ecf); + PortableServer::ObjectId_var reconnection_callback_id = + poa->activate_object (this ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + CORBA::Object_var obj = + poa->id_to_reference (reconnection_callback_id.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + NotifyExt::ReconnectionCallback_var callback = + NotifyExt::ReconnectionCallback::_narrow (obj.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + NotifyExt::ReconnectionRegistry_var registry = + NotifyExt::ReconnectionRegistry::_narrow (ecf ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + this->callback_id_ = registry->register_callback (callback.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + this->id_is_valid_ = true; +} + +///////////////// +// Consumer_Main + +Consumer_Main::Consumer_Main () + : verbose_ (false) + , mode_ (MODE_ANY) + , expect_ (10) + , fail_ (0) + , use_naming_service_ (true) + , serial_number_ (0) + , disconnect_on_exit_ (false) + , id_file_ ("consumer.ids") + , reconnection_callback_ (*this) + , reconnecting_ (false) +{ +} + +Consumer_Main::~Consumer_Main () +{ +} + +int +Consumer_Main::parse_args (int argc, char *argv[]) +{ + int result = 0; + int narg = 1; + bool corba_arg = false; + while (narg < argc && result == 0) + { + int consumed = parse_single_arg (argc - narg, &argv[narg]); + if ( consumed > 0) + { + narg += consumed; + corba_arg = false; + } + else if (ACE_OS::strncmp (argv[narg], "-ORB", 4) == 0) + { + corba_arg = true; + } + else if (corba_arg) + { + // previous argument was a ORB arg. + // current argument is unrecognized + // assume the ORB eats this arg + narg += 1; + corba_arg = false; + } + else + { + ACE_OS::fprintf (stderr, ACE_TEXT ("Unrecognized argument: %s\n"), + argv[narg]); + usage (stderr); + result = -1; + } + } + return result; +} + +int +Consumer_Main::parse_single_arg (int argc, char *argv[]) +{ + int consumed = 0; + if (ACE_OS::strcasecmp (argv[0], "-any") == 0) + { + this->mode_ = MODE_ANY; + consumed = 1; + } + else if (ACE_OS::strcasecmp (argv[0], "-structured") == 0) + { + this->mode_ = MODE_STRUCTURED; + consumed = 1; + } + else if (ACE_OS::strcasecmp (argv[0], "-sequence") == 0) + { + this->mode_ = MODE_SEQUENCE; + consumed = 1; + } + else if (ACE_OS::strcasecmp (argv[0], "-v") == 0) + { + this->verbose_ = true; + consumed = 1; + } + else if (ACE_OS::strcasecmp (argv[0], "-channel") == 0) + { + this->channel_file_= argv[1]; + consumed = 2; + } + else if (ACE_OS::strcasecmp (argv[0], "-expect") == 0 && argc > 1) + { + this->expect_ = ACE_OS::atoi (argv[1]); + consumed = 2; + } + else if (ACE_OS::strcasecmp (argv[0], "-fail") == 0 && argc > 1) + { + this->fail_ = ACE_OS::atoi (argv[1]); + consumed = 2; + } + else if (ACE_OS::strcasecmp (argv[0], "-serial_number") == 0) + { + this->serial_number_= ACE_OS::atoi (argv[1]); + consumed = 2; + } + else if (ACE_OS::strcasecmp (argv[0], "-nonamesvc") == 0) + { + this->use_naming_service_ = false; + consumed = 1; + } + else if (ACE_OS::strcasecmp (argv[0], "-disconnect") == 0) + { + this->disconnect_on_exit_ = true; + consumed = 1; + } + return consumed; +} + +void Consumer_Main::usage(FILE * out)const +{ + ACE_OS::fputs ( + ACE_TEXT ("usage\n") + ACE_TEXT (" -channel filename Where to find a channel number.\n") + ACE_TEXT (" -any or -structured or -sequence\n") + ACE_TEXT (" What type of event to send (pick one, default is -any)\n") + ACE_TEXT (" -expect n How many events of each type are expected.\n") + ACE_TEXT (" -fail n Throw an exception every n events.\n") + ACE_TEXT (" -serial_number n What serial number to start with \n") + ACE_TEXT (" or -1 to disable serial number checking.\n") + ACE_TEXT (" -v Verbose output.\n") + ACE_TEXT (" -disconnect Disconnect from channel on exit (prevents reconnect.) \n") + ACE_TEXT (" -nonamesvc Don't use the name service to find EventChannelFactory\n") + , out); +} + +int Consumer_Main::init (int argc, char *argv[] ACE_ENV_ARG_DECL) +{ + this->orb_ = CORBA::ORB_init(argc, argv, "" ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + if (0 != this->parse_args(argc, argv)) + { + return -1; + } + + CORBA::Object_ptr poa_object = + this->orb_->resolve_initial_references("RootPOA" + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + if (CORBA::is_nil (poa_object)) + { + ACE_ERROR ((LM_ERROR, + " (%P|%t) Unable to initialize the POA.\n")); + return -1; + } + + this->root_poa_ = + PortableServer::POA::_narrow (poa_object ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + PortableServer::POAManager_var poa_manager = + root_poa_->the_POAManager (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + poa_manager->activate (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + if (this->use_naming_service_ ) + { + this->find_notify_factory (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + } + else + { + int ok = resolve_notify_factory (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + if (!ok) + { + return -1; + } + } + + this->reconnecting_ = load_ids (); + + init_event_channel (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + init_consumer_admin (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + switch (this->mode_) + { + case MODE_STRUCTURED: + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Consumer: Listening for %d structured events. Failing every %d events.\n"), + ACE_static_cast (int, this->expect_), + ACE_static_cast (int, this->fail_) + )); + } + this->structured_push_consumer_.set_expectations (this->expect_, this->fail_, this->serial_number_, this->verbose_); + init_structured_proxy_supplier (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + break; + } + case MODE_SEQUENCE: + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Consumer: Listening for %d sequence events. Failing every %d events.\n"), + ACE_static_cast (int, this->expect_), + ACE_static_cast (int, this->fail_) + )); + } + this->sequence_push_consumer_.set_expectations (this->expect_, this->fail_, this->serial_number_, this->verbose_); + init_sequence_proxy_supplier (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + break; + } + case MODE_ANY: + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Consumer: Listening for %d CORBA::Any events. Failing every %d events.\n"), + ACE_static_cast (int, this->expect_), + ACE_static_cast (int, this->fail_) + )); + } + this->any_push_consumer_.set_expectations (this->expect_, this->fail_, this->serial_number_, this->verbose_); + init_any_proxy_supplier (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + break; + } + default: + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Consumer: Unknown listening mode.\n") + )); + break; + } + } + + this->reconnection_callback_.init ( + this->root_poa_.in (), + this->ecf_.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + save_ids (); + return 0; +} +void +Consumer_Main::save_ids() +{ + FILE *idf = + ACE_OS::fopen (this->id_file_.c_str (), "w"); + + if (idf != 0) + { + int endflag = 12345; + int imode = ACE_static_cast (int, this->mode_); + ACE_OS::fprintf (idf, + "%d,%d,%d,%d,%d,%d,%d,\n", + imode, + ec_id_, + sa_id_, + structured_proxy_id_, + sequence_proxy_id_, + any_proxy_id_, + endflag); + ACE_OS::fclose (idf); + } +} + +bool +Consumer_Main::load_ids() +{ + bool ok = false; + FILE *idf = + ACE_OS::fopen (this->id_file_.c_str (), "w"); + + if (idf != 0) + { + int field = 0; + + char buffer[100]; + ACE_OS::fgets (buffer, sizeof(buffer), idf); + ACE_OS::fclose (idf); + char * pb = buffer; + while (*pb != 0) + { + char * eb = ACE_OS::strchr (pb, ','); + char * nb = eb + 1; + if (eb == 0) + { + eb = pb + ACE_OS::strlen (pb); + nb = eb; + } + else + { + *eb = 0; + } + if (pb < eb) + { + int value = ACE_OS::atoi(pb); + switch (field) + { + case 1: + this->mode_ = static_cast<Mode_T> (value); + break; + case 2: + this->ec_id_ = value; + break; + case 3: + this->sa_id_ = value; + break; + case 4: + this->structured_proxy_id_ = value; + break; + case 5: + this->sequence_proxy_id_ = value; + break; + case 6: + this->any_proxy_id_ = value; + break; + case 7: + ok = value == 12345; + break; + default: + ACE_OS::fprintf (stderr, ACE_TEXT ("Warning: too many fields in saved id file.\n")); + ok = false; + break; + } + } + pb = nb; + } + } + return ok; +} + +void +Consumer_Main::reconnect ( + CosNotifyChannelAdmin::EventChannelFactory_ptr dest_factory + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer begin ReconnectRegistry based reconnection\n") + )); + } + this->ecf_ = CosNotifyChannelAdmin::EventChannelFactory::_duplicate (dest_factory); + this->reconnecting_ = true; + init_event_channel (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + + init_consumer_admin (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + + switch (this->mode_) + { + case MODE_STRUCTURED: + { + init_structured_proxy_supplier (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + break; + } + + case MODE_SEQUENCE: + { + init_sequence_proxy_supplier (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + break; + } + + case MODE_ANY : + { + init_any_proxy_supplier (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + break; + } + } + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer ReconnectRegistry based reconnection complete\n") + )); + } +} + + +int +Consumer_Main::resolve_naming_service (ACE_ENV_SINGLE_ARG_DECL) +{ + // ignore redundant calls + if (CORBA::is_nil (this->naming_context_.in ())) + { + CORBA::Object_var naming_obj = + this->orb_->resolve_initial_references (NAMING_SERVICE_NAME + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + + this->naming_context_ = + CosNaming::NamingContext::_narrow (naming_obj.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + } + + return !CORBA::is_nil (this->naming_context_.in ()); +} + +int +Consumer_Main::find_notify_factory (ACE_ENV_SINGLE_ARG_DECL) +{ + int status = this->resolve_naming_service (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + if (status) + { + CosNaming::Name name (1); + name.length (1); + name[0].id = CORBA::string_dup (NOTIFY_FACTORY_NAME); + + CORBA::Object_var obj = + this->naming_context_->resolve (name + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + + this->ecf_ = + CosNotifyChannelAdmin::EventChannelFactory::_narrow ( + obj.in () + ACE_ENV_ARG_PARAMETER + ); + ACE_CHECK_RETURN(0); + } + return ! CORBA::is_nil (this->ecf_.in ()); +} + +int +Consumer_Main::resolve_notify_factory (ACE_ENV_SINGLE_ARG_DECL) +{ + CORBA::Object_var factory_obj = + this->orb_->resolve_initial_references (NOTIFY_FACTORY_NAME + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + + this->ecf_ = + CosNotifyChannelAdmin::EventChannelFactory::_narrow ( + factory_obj.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + return ! CORBA::is_nil (this->ecf_.in ()); +} + +void +Consumer_Main::init_event_channel (ACE_ENV_SINGLE_ARG_DECL) +{ + bool ok = false; + if (this->reconnecting_) + { + ACE_TRY_NEW_ENV + { + this->ec_ = this->ecf_->get_event_channel ( + this->ec_id_ + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + ok = ! CORBA::is_nil (this->ec_.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer: Reconnect to event channel %d\n"), + ACE_static_cast (int, this->ec_id_) + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + + // if we don't have a channel yet, and a channel id file was specified + // try to read from it + if (!ok && this->channel_file_.length () > 0) + { + FILE * chf = ACE_OS::fopen (this->channel_file_.c_str (), "r"); + if (chf != 0) + { + char buffer[100]; + ACE_OS::fgets (buffer, sizeof(buffer), chf); + ACE_OS::fclose (chf); + this->ec_id_ = ACE_OS::atoi (buffer); + + ACE_DECLARE_NEW_ENV; + ACE_TRY_EX (unique_label_1) + { + this->ec_ = this->ecf_->get_event_channel ( + this->ec_id_ + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK_EX (unique_label_1) + ok = ! CORBA::is_nil (this->ec_.in ()); + if (ok) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) supplier: Connect to Existing event channel %d\n"), + ACE_static_cast (int, this->ec_id_) + )); + } + // kill the channel filename so we don't overwrite the file + this->channel_file_ = ""; + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + } + + if (!ok) + { + CosNotification::QoSProperties qosprops(7); + qosprops.length(7); + CORBA::ULong i = 0; +#ifdef DISABLE_PROPERTIES_TODO + qosprops[i].name = CORBA::string_dup(CosNotification::EventReliability); + qosprops[i++].value <<= CosNotification::Persistent; + qosprops[i].name = CORBA::string_dup(CosNotification::ConnectionReliability); + qosprops[i++].value <<= CosNotification::Persistent; // Required, or we won't persist much + qosprops[i].name = CORBA::string_dup(CosNotification::Priority); + qosprops[i++].value <<= CosNotification::HighestPriority; + qosprops[i].name = CORBA::string_dup(CosNotification::Timeout); + qosprops[i++].value <<= (TimeBase::TimeT) 42 * 10000; // 42ms + qosprops[i].name = CORBA::string_dup(CosNotification::StopTimeSupported); + qosprops[i++].value <<= CORBA::Any::from_boolean(1); + qosprops[i].name = CORBA::string_dup(CosNotification::MaximumBatchSize); + qosprops[i++].value <<= (CORBA::Long)2; + qosprops[i].name = CORBA::string_dup(CosNotification::PacingInterval); + qosprops[i++].value <<= (TimeBase::TimeT) 50 * 10000; // 50ms +#endif + qosprops.length (i); + CosNotification::AdminProperties adminprops(4); + adminprops.length(4); + i = 0; +#ifdef DISABLE_PROPERTIES_TODO + adminprops[i].name = CORBA::string_dup(CosNotification::MaxQueueLength); + adminprops[i++].value <<= (CORBA::Long) 1234; + adminprops[i].name = CORBA::string_dup(CosNotification::MaxSuppliers); + adminprops[i++].value <<= (CORBA::Long) 1000; + adminprops[i].name = CORBA::string_dup(CosNotification::MaxConsumers); + adminprops[i++].value <<= (CORBA::Long) 1000; + adminprops[i].name = CORBA::string_dup(CosNotification::RejectNewEvents); + adminprops[i++].value <<= CORBA::Any::from_boolean(1); +#endif + adminprops.length(i); + + ec_ = this->ecf_->create_channel ( + qosprops, + adminprops, + this->ec_id_ + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + ok = ! CORBA::is_nil (ec_.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer: Create event channel %d\n"), + ACE_static_cast (int, this->ec_id_) + )); + } + } + + if (ok && this->channel_file_.length() > 0) + { + FILE * chf = ACE_OS::fopen (this->channel_file_.c_str (), "r"); + if (chf != 0) + { + char buffer[100]; + ACE_OS::fgets (buffer, sizeof(buffer), chf); + ACE_OS::fclose (chf); + this->ec_id_ = ACE_OS::atoi (buffer); + } + } +} + +CosNotifyChannelAdmin::AdminID default_admin_id = ACE_static_cast (CosNotifyChannelAdmin::AdminID, -1); + +void +Consumer_Main::init_consumer_admin (ACE_ENV_SINGLE_ARG_DECL) +{ + bool ok = false; + if (this->reconnecting_ && this->sa_id_ != default_admin_id) + { + ACE_TRY_EX(ONE) + { + this->sa_ = this->ec_->get_consumeradmin( + this->sa_id_ + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK_EX(ONE); + ok = ! CORBA::is_nil (this->sa_.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer: Reconnect to consumer admin %d\n"), + ACE_static_cast (int, this->sa_id_) + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + + if (!ok) + { + ACE_TRY_EX(TWO) + { + this->sa_ = this->ec_->default_consumer_admin (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK_EX(TWO); + ok = ! CORBA::is_nil (this->sa_.in ()); + this->sa_id_ = default_admin_id; + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer: Using default consumer admin\n") + )); + } + else if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer: No default consumer admin\n") + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + + if (!ok) + { + this->sa_ = this->ec_->new_for_consumers( + CosNotifyChannelAdmin::OR_OP, + this->sa_id_ + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + ok = ! CORBA::is_nil (this->sa_.in ()); + +#ifdef TEST_SET_QOS + // temporary: be sure we can set qos properties here + if (ok) + { + CosNotification::QoSProperties qosprops(2); + CORBA::ULong i = 0; + qosprops.length(2); + + qosprops[i].name = CORBA::string_dup(CosNotification::EventReliability); + qosprops[i++].value <<= CosNotification::Persistent; + qosprops[i].name = CORBA::string_dup(CosNotification::ConnectionReliability); + qosprops[i++].value <<= CosNotification::Persistent; // Required, or we won't persist much + qosprops.length(i); + this->sa_->set_qos (qosprops ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } +#endif + + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer: Create new consumer admin %d\n"), + ACE_static_cast (int, this->sa_id_) + )); + } + } +} + +void +Consumer_Main::init_structured_proxy_supplier (ACE_ENV_SINGLE_ARG_DECL) +{ + bool ok = false; + CosNotifyChannelAdmin::ProxySupplier_var proxy; + if (this->reconnecting_) + { + ACE_TRY_NEW_ENV + { + proxy = this->sa_->get_proxy_supplier ( + this->structured_proxy_id_ + ACE_ENV_ARG_PARAMETER + ); + ACE_TRY_CHECK; + ok = ! CORBA::is_nil (proxy.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer: Reconnect to proxy supplier %d\n"), + ACE_static_cast (int, this->structured_proxy_id_) + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + + if (!ok) + { + proxy = this->sa_->obtain_notification_push_supplier( + CosNotifyChannelAdmin::STRUCTURED_EVENT, + this->structured_proxy_id_ + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + ok = ! CORBA::is_nil (proxy.in ()); +#ifdef TEST_SET_QOS + // temporary + if (ok) + { + set_proxy_qos (proxy.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } +#endif // TEST_SET_QOS + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer: Create new proxy %d\n"), + ACE_static_cast (int, this->structured_proxy_id_) + )); + } + } + this->structured_proxy_push_supplier_ = + CosNotifyChannelAdmin::StructuredProxyPushSupplier::_narrow(proxy.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + if (CORBA::is_nil (this->structured_proxy_push_supplier_.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) init_structured_proxy_supplier received nil ProxySupplier\n") + )); + ACE_THROW (CORBA::OBJECT_NOT_EXIST ()); + } + + if (CORBA::is_nil (this->structured_push_consumer_ref_.in ())) + { + PortableServer::ObjectId_var push_consumer_id = + this->root_poa_->activate_object ( + &(this->structured_push_consumer_) ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + CORBA::Object_var obj = + this->root_poa_->id_to_reference (push_consumer_id.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + this->structured_push_consumer_ref_ = + CosNotifyComm::StructuredPushConsumer::_narrow (obj.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + + if (CORBA::is_nil (this->structured_push_consumer_ref_.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Consumer: Error activating structured push consumer\n") + )); + + ACE_THROW (CORBA::BAD_PARAM()); + } + + this->structured_proxy_push_supplier_->connect_structured_push_consumer ( + this->structured_push_consumer_ref_.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + this->structured_push_consumer_.set_connected(true); +} + +void +Consumer_Main::init_sequence_proxy_supplier (ACE_ENV_SINGLE_ARG_DECL) +{ + bool ok = false; + CosNotifyChannelAdmin::ProxySupplier_var proxy; + if (this->reconnecting_) + { + ACE_TRY_NEW_ENV + { + proxy = this->sa_->get_proxy_supplier( + this->sequence_proxy_id_ + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + ok = ! CORBA::is_nil (proxy.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer: Reconnect to proxy %d\n"), + ACE_static_cast (int, this->sequence_proxy_id_) + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + + if (!ok) + { + proxy = this->sa_->obtain_notification_push_supplier( + CosNotifyChannelAdmin::SEQUENCE_EVENT, + this->sequence_proxy_id_ + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + ok = ! CORBA::is_nil (proxy.in ()); +#ifdef TEST_SET_QOS + // temporary + if (ok) + { + set_proxy_qos (proxy.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } +#endif // TEST_SET_QOS + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer: Create new proxy %d\n"), + ACE_static_cast (int, this->sequence_proxy_id_) + )); + } + } + this->sequence_proxy_push_supplier_ = + CosNotifyChannelAdmin::SequenceProxyPushSupplier::_narrow(proxy.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + if (CORBA::is_nil (this->sequence_proxy_push_supplier_.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Consumer: Received wrong type of push supplier proxy %d\n"), + ACE_static_cast (int, this->sequence_proxy_id_) + )); + + ACE_THROW (CORBA::BAD_PARAM()); + } + + if (CORBA::is_nil (this->sequence_push_consumer_ref_.in ())) + { + PortableServer::ObjectId_var push_consumer_id = + this->root_poa_->activate_object ( + &(this->sequence_push_consumer_) ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + CORBA::Object_var obj = + this->root_poa_->id_to_reference (push_consumer_id.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + this->sequence_push_consumer_ref_ = + CosNotifyComm::SequencePushConsumer::_narrow (obj.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + if (CORBA::is_nil (this->sequence_push_consumer_ref_.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Consumer: Error activating sequence push consumer\n") + )); + + ACE_THROW (CORBA::BAD_PARAM()); + } + + this->sequence_proxy_push_supplier_->connect_sequence_push_consumer ( + this->sequence_push_consumer_ref_.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + this->sequence_push_consumer_.set_connected(true); + +} + + +void +Consumer_Main::set_proxy_qos (CosNotifyChannelAdmin::ProxySupplier_ptr proxy + ACE_ENV_ARG_DECL) +{ + // temporary: be sure we can set qos properties for proxyw + CosNotification::QoSProperties qosprops(2); + CORBA::ULong i = 0; + qosprops.length(2); + + qosprops[i].name = CORBA::string_dup(CosNotification::EventReliability); + qosprops[i++].value <<= CosNotification::Persistent; + qosprops[i].name = CORBA::string_dup(CosNotification::ConnectionReliability); + qosprops[i++].value <<= CosNotification::Persistent; // Required, or we won't persist much + qosprops.length(i); + proxy->set_qos (qosprops ACE_ENV_ARG_PARAMETER); + ACE_CHECK; +} + +void +Consumer_Main::init_any_proxy_supplier (ACE_ENV_SINGLE_ARG_DECL) +{ + bool ok = false; + CosNotifyChannelAdmin::ProxySupplier_var proxy; + if (this->reconnecting_) + { + ACE_TRY_NEW_ENV + { + proxy = this->sa_->get_proxy_supplier( + this->any_proxy_id_ + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + ok = ! CORBA::is_nil (proxy.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer: Reconnect to proxy %d\n"), + ACE_static_cast (int, this->any_proxy_id_) + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + + if (!ok) + { + proxy = this->sa_->obtain_notification_push_supplier( + CosNotifyChannelAdmin::ANY_EVENT, + this->any_proxy_id_ + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + ok = ! CORBA::is_nil (proxy.in ()); + +#ifdef TEST_SET_QOS + // temporary + if (ok) + { + set_proxy_qos (proxy.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } +#endif // TEST_SET_QOS + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Consumer: Create new proxy\n"), + ACE_static_cast (int, this->any_proxy_id_) + )); + } + } + this->any_proxy_push_supplier_ = + CosNotifyChannelAdmin::ProxyPushSupplier::_narrow(proxy.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + if (CORBA::is_nil (this->any_proxy_push_supplier_.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Consumer: Received wrong type of push supplier proxy %d\n"), + ACE_static_cast (int, this->sequence_proxy_id_) + )); + ACE_THROW (CORBA::BAD_PARAM()); + } + if (CORBA::is_nil (this->any_push_consumer_ref_.in ())) + { + PortableServer::ObjectId_var push_consumer_id = + this->root_poa_->activate_object ( + &(this->any_push_consumer_) ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + CORBA::Object_var obj = + this->root_poa_->id_to_reference (push_consumer_id.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + this->any_push_consumer_ref_ = + CosNotifyComm::PushConsumer::_narrow (obj.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + + if (CORBA::is_nil (this->any_push_consumer_ref_.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Consumer:Error activating push consumer\n") + )); + + ACE_THROW (CORBA::BAD_PARAM()); + } + this->any_proxy_push_supplier_->connect_any_push_consumer ( + this->any_push_consumer_ref_.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + this->any_push_consumer_.set_connected(true); +} + +int Consumer_Main::fini (ACE_ENV_SINGLE_ARG_DECL) +{ + + this->reconnection_callback_.fini (ACE_ENV_SINGLE_ARG_PARAMETER); + if (this->disconnect_on_exit_) + { + if (!CORBA::is_nil (this->structured_proxy_push_supplier_.in ())) + { + this->structured_proxy_push_supplier_->disconnect_structured_push_supplier (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-4); + } + if (!CORBA::is_nil (this->sequence_proxy_push_supplier_.in ())) + { + this->sequence_proxy_push_supplier_->disconnect_sequence_push_supplier (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-4); + } + if (!CORBA::is_nil (this->any_proxy_push_supplier_.in ())) + { + this->any_proxy_push_supplier_->disconnect_push_supplier (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-4); + } + if (!CORBA::is_nil (this->sa_.in ()) && this->sa_id_ != default_admin_id) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) destroy admin %d\n"), + ACE_static_cast(int, this->sa_id_) + )); + } + this->sa_->destroy(); + } + } + this->orb_->shutdown (); + return 0; +} + + +int Consumer_Main::run (ACE_ENV_SINGLE_ARG_DECL) +{ + int result = 0; + + ////////////////////////////////// + // Run the event loop for the ORB. + // Initial run to initialize the orb + ACE_Time_Value tv(1,0); + this->orb_->run (tv ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(-1); + + while (this->structured_push_consumer_.received () < this->expect_ + && this->sequence_push_consumer_.received () < this->expect_ + && this->any_push_consumer_.received () < this->expect_ + ) + { + ACE_Time_Value work_tv(1,0); + // keep the orb alive -- listenting for reconnect + this->orb_->perform_work (work_tv ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(-1); + } + + // see if consumers detected errors + if (this->structured_push_consumer_.has_problem () + || this->sequence_push_consumer_.has_problem () + || this->any_push_consumer_.has_problem ()) + { + result = -3; + } + return result; +} + +int +main (int argc, char *argv[]) +{ + int result = -1; + Consumer_Main app; + ACE_TRY_NEW_ENV + { + result = app.init(argc, argv ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK + + if (result == 0) + { + result = app.run (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + } + if (result == 0) + { + app.fini (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + } + } + ACE_CATCHANY + { + ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, + "Consumer::main\t\n"); + result = -1; + } + ACE_ENDTRY; + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Consumer exits: code %d\n"), + result + )); + return result; +} + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.h b/TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.h new file mode 100644 index 00000000000..0f21447744e --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/Consumer.h @@ -0,0 +1,300 @@ +/* -*- C++ -*- */ +// $Id$ +// ========================================================================== +// +// = FILENAME +// Consumer.h +// +// = DESCRIPTION +// Test Consumer reconnect to existing channel/admin/proxy Notification Service +// +// = AUTHOR +// Dale Wilson <wilson_d@ociweb.com> +// +// ========================================================================== + +#ifndef RECONNECTNG_CONSUMER_H +#define RECONNECTNG_CONSUMER_H + +//#if defined(_MSC_VER) && (_MSC_VER >= 1200) +//#pragma warning(pop) +//#endif /* _MSC_VER */ + + +#include "orbsvcs/CosNotifyChannelAdminC.h" +#include "orbsvcs/CosNamingC.h" +#include "orbsvcs/NotifyExtS.h" +#include "ace/SString.h" + +class Consumer_Main; + +class StructuredPushConsumer_i : public virtual POA_CosNotifyComm::StructuredPushConsumer +{ +public: + StructuredPushConsumer_i (); + virtual void offer_change ( + const CosNotification::EventTypeSeq & added, + const CosNotification::EventTypeSeq & removed + ACE_ENV_ARG_DECL + ) + ACE_THROW_SPEC (( + CORBA::SystemException, + CosNotifyComm::InvalidEventType)); + + virtual void push_structured_event ( + const CosNotification::StructuredEvent & notification + ACE_ENV_ARG_DECL + ) + ACE_THROW_SPEC ((CORBA::SystemException, + CosEventComm::Disconnected)); + + virtual void disconnect_structured_push_consumer ( + ACE_ENV_SINGLE_ARG_DECL + ) + ACE_THROW_SPEC ((CORBA::SystemException)); + + size_t received () const; + void set_expectations (size_t expecte, size_t fail, size_t serial_number, bool verbose); + bool has_problem () const; + void set_connected (bool flag); + bool is_connected () const; + +private: + void check_serial_number (CORBA::ULong seq); + +private: + bool verbose_; + size_t received_; + size_t expect_; + size_t fail_; + size_t may_discard_; + size_t serial_number_; + size_t exceptions_thrown_; + bool problem_; + bool connected_; +}; + +class SequencePushConsumer_i : public virtual POA_CosNotifyComm::SequencePushConsumer +{ +public: + SequencePushConsumer_i (); + virtual void offer_change ( + const CosNotification::EventTypeSeq & added, + const CosNotification::EventTypeSeq & removed + ACE_ENV_ARG_DECL + ) + ACE_THROW_SPEC (( + CORBA::SystemException, + CosNotifyComm::InvalidEventType)); + + virtual void push_structured_events ( + const CosNotification::EventBatch & notifications + ACE_ENV_ARG_DECL + ) + ACE_THROW_SPEC ((CORBA::SystemException, + CosEventComm::Disconnected)); + + virtual void disconnect_sequence_push_consumer ( + ACE_ENV_SINGLE_ARG_DECL + ) + ACE_THROW_SPEC ((CORBA::SystemException)); + + size_t received () const; + void set_expectations (size_t expecte, size_t fail, size_t serial_number, bool verbose); + bool has_problem () const; + void set_connected (bool flag); + bool is_connected () const; + +private: + void check_serial_number (CORBA::ULong seq); + +private: + bool verbose_; + size_t received_; + size_t expect_; + size_t fail_; + size_t may_discard_; + size_t serial_number_; + size_t exceptions_thrown_; + bool problem_; + bool connected_; +}; + +class AnyPushConsumer_i : public virtual POA_CosNotifyComm::PushConsumer +{ +public: + AnyPushConsumer_i (); + + virtual void offer_change ( + const CosNotification::EventTypeSeq & added, + const CosNotification::EventTypeSeq & removed + ACE_ENV_ARG_DECL + ) + ACE_THROW_SPEC (( + CORBA::SystemException, + CosNotifyComm::InvalidEventType)); + + virtual void push ( + const CORBA::Any & data + ACE_ENV_ARG_DECL + ) + ACE_THROW_SPEC ((CORBA::SystemException, + CosEventComm::Disconnected)); + + virtual void disconnect_push_consumer ( + ACE_ENV_SINGLE_ARG_DECL + ) + ACE_THROW_SPEC ((CORBA::SystemException)); + + size_t received () const; + void set_expectations (size_t expecte, size_t fail, size_t serial_number, bool verbose); + bool has_problem () const; + void set_connected (bool flag); + bool is_connected () const; + +private: + void check_serial_number (CORBA::ULong seq); + +private: + bool verbose_; + size_t received_; + size_t expect_; + size_t fail_; + size_t may_discard_; + size_t serial_number_; + size_t exceptions_thrown_; + bool problem_; + bool connected_; +}; + +class ReconnectionCallback_i : public virtual POA_NotifyExt::ReconnectionCallback +{ +public: + ReconnectionCallback_i (Consumer_Main & consumer_main); + + virtual ~ReconnectionCallback_i (); + + void init ( + PortableServer::POA_ptr poa, + CosNotifyChannelAdmin::EventChannelFactory_ptr ecf_ + ACE_ENV_ARG_DECL); + + void fini (ACE_ENV_SINGLE_ARG_DECL); + + size_t reconnect_count () const; + + virtual void reconnect ( + CORBA::Object_ptr reconnection + ACE_ENV_ARG_DECL + ) ACE_THROW_SPEC ((CORBA::SystemException)); + + virtual CORBA::Boolean is_alive (ACE_ENV_SINGLE_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + +private: + Consumer_Main & consumer_main_; + bool id_is_valid_; + NotifyExt::ReconnectionRegistry::ReconnectionID callback_id_; + CosNotifyChannelAdmin::EventChannelFactory_var ecf_; + size_t reconnect_count_; +}; + +class Consumer_Main +{ + public: + Consumer_Main (); + ~Consumer_Main (); + + int parse_args (int argc, char *argv[]); + int parse_single_arg (int argc, char *argv[]); + + int init (int argc, char *argv[] ACE_ENV_ARG_DECL); + int run (ACE_ENV_SINGLE_ARG_DECL); + int fini (ACE_ENV_SINGLE_ARG_DECL); + void usage (FILE * log) const; + + void reconnect ( + CosNotifyChannelAdmin::EventChannelFactory_ptr dest_factory + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + + private: + /// Find naming service. + int resolve_naming_service (ACE_ENV_SINGLE_ARG_DECL); + + /// Resolve the Notify factory from the Naming service. + int find_notify_factory (ACE_ENV_SINGLE_ARG_DECL); + + /// Resolve the Notify factory using resolve_initial_reference ("NotifyEventChannelFactory") + int resolve_notify_factory (ACE_ENV_SINGLE_ARG_DECL); + + void init_event_channel (ACE_ENV_SINGLE_ARG_DECL); + void init_consumer_admin (ACE_ENV_SINGLE_ARG_DECL); + void init_structured_proxy_supplier (ACE_ENV_SINGLE_ARG_DECL); + void init_sequence_proxy_supplier (ACE_ENV_SINGLE_ARG_DECL); + void init_any_proxy_supplier (ACE_ENV_SINGLE_ARG_DECL); + + void set_proxy_qos (CosNotifyChannelAdmin::ProxySupplier_ptr proxy ACE_ENV_ARG_DECL); + + void save_ids(); + bool load_ids(); + + //////////////////// + // forbidden methods + private: + Consumer_Main (const Consumer_Main & rhs); + Consumer_Main & operator = (const Consumer_Main & rhs); + + //////////////// + // Data members + private: + + // set by command line parameters + bool verbose_; // -v make a glorious noise + enum Mode_T{ + MODE_ANY, + MODE_STRUCTURED, + MODE_SEQUENCE} mode_; // -any, -structured, or -sequence + ACE_CString channel_file_; // -channel fileneame + size_t expect_; // -expect n + size_t fail_; // -fail n + bool use_naming_service_; // -nonamesvc + size_t serial_number_; // -serial_number + bool disconnect_on_exit_; // -disconnect + size_t structured_count_; + size_t sequence_count_; + size_t any_count_; + + ACE_CString id_file_; // -ids + CORBA::ORB_var orb_; + PortableServer::POA_var root_poa_; + CosNaming::NamingContext_var naming_context_; + CosNotifyChannelAdmin::EventChannelFactory_var ecf_; + + CosNotifyChannelAdmin::EventChannel_var ec_; + CosNotifyChannelAdmin::ChannelID ec_id_; + + CosNotifyChannelAdmin::ConsumerAdmin_var sa_; + CosNotifyChannelAdmin::AdminID sa_id_; + + CosNotifyChannelAdmin::StructuredProxyPushSupplier_var structured_proxy_push_supplier_; + CosNotifyChannelAdmin::ProxyID structured_proxy_id_; + StructuredPushConsumer_i structured_push_consumer_; + CosNotifyComm::StructuredPushConsumer_var structured_push_consumer_ref_; + + CosNotifyChannelAdmin::SequenceProxyPushSupplier_var sequence_proxy_push_supplier_; + CosNotifyChannelAdmin::ProxyID sequence_proxy_id_; + SequencePushConsumer_i sequence_push_consumer_; + CosNotifyComm::SequencePushConsumer_var sequence_push_consumer_ref_; + + CosNotifyChannelAdmin::ProxyPushSupplier_var any_proxy_push_supplier_; + CosNotifyChannelAdmin::ProxyID any_proxy_id_; + AnyPushConsumer_i any_push_consumer_; + CosNotifyComm::PushConsumer_var any_push_consumer_ref_; + + ReconnectionCallback_i reconnection_callback_; + + bool reconnecting_; +}; + +#endif /* RECONNECTNG_CONSUMER_H */ diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/README b/TAO/orbsvcs/tests/Notify/Reconnecting/README new file mode 100644 index 00000000000..723c0a4f730 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/README @@ -0,0 +1,351 @@ +$Id$ + +README for the Notification Service Reconnection Test +----------------------------------------------------- + +Implementation notes +-------------------- + +Notification Service Supplier/Consumer reconnection test. + +This directory contains: + + Supplier.cpp -- source for a configurable event supplier + Supplier.h + Consumer.cpp -- source for a configurable consumer for events produced + Consumer.h by a Supplier + run_ns.pl -- a script to start the Notification Service manually + run_supplier.pl -- a script to start Supplier manually + run_consumer.pl -- a script to start Consumer manually + run_test.pl -- a script to run several tests of the Reliable + Notification Service + ns_st.conf -- configures the Notification Service for single + thread operation with no persistence support. + ns_mt.conf -- configures the Notification Service for multi- + threaded operation with no persistence support. + ns_st_topo.conf -- configures the Notification Service for single + thread operation with support for topological, + but not event persistence. + ns_mt_topo.conf -- configures the Notification Service for multi- + threaded operation with support for topological, + but not event persistence. + ns_st_both.conf -- configures the Notification Service for single + thread operation with support for both topological, + and event persistence. + ns_mt_both.conf -- configures the Notification Service for multi- + threaded operation with support for both topological, + and event persistence. + event.conf -- configures the Notification Service for event + persistence without topology persistence. This is + an invalid configuration and should cause the + Notification Service to refuse to start. + Reconnecting.mpc -- a configuration/build file for MPC + README -- this file + +Supplier +-------- +This program connects to the Notification Service and generates events based +on command line parameters. + + -nonamesvc Don't use the Naming Service to find + EventChannelFactory + -channel filename Where to find a channel number + -any or -str or -seq What type of event to send (pick one, default is -any) + -send n How many events to send + -pause n Pause after sending n events + Signal the pause by writing to file "Supplier.paused" + -serial_number n What serial number to start with + -v Verbose output + +Because the Supplier and Consumer share many command line options, the +descriptions of these options will be combined below. + +Consumer +-------- +This program connects to the Notification Service and consumes events from +the Supplier. + + -nonamesvc Don't use the Naming Service to find + EventChannelFactory + -channel filename Where to store a channel number so the Supplier can + find it + -any or -str or -seq What type of event supplier will send (pick one, + default: -any) + -expect n How many events are expected. + -fail n Simulate a recoverable failure every n events. + -serial_number n What serial number to expect first. If -1 is + used, then serial number checking is disabled. + This allows testing the consumer with multiple + Suppliers. + -disconnect Disconnect from notfication service cleanly + (no reconnect will be possible) + -v Verbose output. + +Command line option: -nonamesvc +------------------------------- +There are several techniques that Notification Service clients (Suppliers +and Consumers) may use to find and connect to the Notification Service. +One common technique is for the Notification Service to register an Event +Channel Factory with the Naming Service using a well-known name (specified in +the CORBA standard.) + +Although this technique is a good one for use in a system that already depends +on the Naming Service, the test scripts in this directory do not depend on the +Naming Service. When this option is specified, the Supplier and Consumer use +"resolve_initial_references ()" to find the Notification Service. + +When this option is used, the ORB option -ORBInitRef must also be used to +define an initial reference to the Notification Service. + +Command line option: -channel filename +-------------------------------------- +The Notification Service has the ability to support several channels +simultaneously. For these tests to work, the Supplier and Consumer must +use the same channel. There are several techniques the Consumer(s) and +Supplier(s) can use to select which channel to use. These programs use a +shared file to communicate the channel number from the Consumer that creates +the channel to the Supplier that uses it. + +When the Consumer starts up but is not reconnecting to an existing service, +it creates a new channel and writes the channel ID to the file specified by +this command (if no -channel option is given, the channel ID is not written.) + +When the Supplier starts up, but is not reconnecting to an existing service, +it attempts to read the channel ID from the file specified by this option. +If it is successful it uses that channel ID to send events. + +Command line options: -any or -str or -seq +------------------------------------------ +The Notification Service supports three types of Events. Any events are +like those used by the Event Service (an ancestor to the Notification +Service). Structured events and Sequence events are events supported only +by the Notification Service. See the TAO Developer's Guide or the CORBA +specification for more details. + +Only one of these three options should be specified. If none of these +is specified, the default is "-any". + +Command line option: -send n +---------------------------- +This Supplier-only option tells the Supplier how many events to send. +After it has sent that many events, the Supplier will shut down. + +Command line option: -expect n +------------------------------ +This Consumer-only option tells the Consumer how many events to expect. +After it has received that many events, the Consumer will shut down. + +Command line option: -fail n +------------------------------ +This Consumer-only option tells the Consumer to throw an exception +(CORBA::UNKNOWN) every n events. This simulates a recoverable error in +the consumer. After throwing the exception, the consumer continues +to listen for incoming events. It expects the event it was processing +to be retransmitted. + +Because of the retransmission, the use of the -fail option may be +counterintuitive. If the consumer options are "-expect 10 -fail 4" then +it will receive events 0, 1, 2, and fail on event 3. It will then +receive 3, 4, 5, and fail on event 6. Then it will receive 6, 7, 8, +and fail on event 9. Finally it will receive the retransmission of event +9 and exit. + +Command line option: -pause n +----------------------------- +This Supplier-only option is used during testing. The Supplier will send +the specified number of events then wait for the Notification Service to +stop and restart before sending the remaining events. + +To signal test scripts that a pause has happened, the Supplier will create +a file named "Supplier.pause" This file can be used to synchronize a +script with a running Supplier. It has no other purpose. + +Obviously the -pause option should specify a smaller number than the -send +option. If this option is not used, no pause will occur. + +Command line option: -serial_number n +------------------------------------- +Each event sent by the the Supplier has a sequential serial number. As the +Consumer receives events, it checks to see that the events arrived in serial +number order. Missing or duplicated events will be detected by the Consumer. + +This option tells the Supplier what serial number to use for the first event +it sends, and the Consumer what serial number to expect in the first event +it receives. + +For the Consumer only, a value of -1 disables checking of incoming serial +numbers. This should be used when the Consumer is receiving events from +multiple suppliers. + +Command line option: -v +----------------------- +This option enables verbose messages. The Supplier and Consumer are +relatively silent during normal operation -- displaying messages only when +something goes wrong. If this verbose option is specified, more detailed +progress messages will be displayed. + +Reconnection +------------ +Reconnection to the Notification Service is based on ID numbers assigned to +the objects within the Notification Service (objects like Channels, Admins, +and Proxies). After initially starting up, the supplier writes the IDs it +needs to preserve to a file named Supplier.ids. The Consumer writes its +IDs to Consumer.ids. + +When a client (Supplier or Consumer) starts up, it looks for its corresponding +".ids" file. If the file is found, the client attempts to reconnect to an +existing Notification Service using these IDs. If the file is not found, or +the reconnection fails, the client falls back on its normal startup procedure. + +In addition, a running client can receive a request for reconnection from +the Notification Service. When it does so, it uses the saved ID numbers to +complete the reconnection process. + +Programming Style +----------------- +The Supplier and Consumer source files were designed to be complete, +stand-alone applications. Other than their basic dependency on ACE, TAO, +and CORBA, they avoid using outside facilities. For example, there is a +Notification Tests library used by many Notification Service tests that +encapsulates connections to the Notification Service and typical CORBA +application issues. Because these programs were intended to illustrate +everything necessary for a client application to work with a reliable +Notification Service, this library is not used. + +Obviously a real-world application should take advantage of such helper +classes to allow the developer to concentrate on the domain problem for +which the application is written. + +Also these programs use ACE-style platform independence techniques. +Applications that do not need to support the wide variety of platforms +supported by ACE and TAO can relax some of these coding techniques. + +run_test.pl +----------- +The run_test.pl script runs tests of different cases in which +reliable topology is needed. The following command line options can +be given to the test script: + +run_test.pl: command line options -any, -str, or -seq +----------------------------------------------------- +Specify one of these options to determine what type of event will be used +during the test. The default if none of these options is present is "-any". + +run_test.pl: command line option -v +-------------------------------------------- +This option controls the verbosity of the test script and the Supplier and +Consumer applications. When it is present, a detailed step-by-step +report is produced by the test. + +run_test.pl: Test #1: Supplier reconnection. +-------------------------------------------- +All persistent information is discarded before the test starts. The test +script starts the Notification Service, a Consumer and a Supplier. + +The Consumer is configured to receive 20 events. The Supplier is configured +to send ten events. + +After sending ten events, the Supplier exits -- simulating a Supplier failure. +The test script starts a new copy of the Supplier. The new Supplier is +configured to send ten events starting with event number 10. +It uses information saved by the previous supplier to reconnect to the same +channel, admin, and proxy in the Notification Services. +The Suppler sends the remaining ten events then exists. The Consumer having +received the 20 events it expects, exits as well and the test is complete. + +This demonstrates that a Supplier can stop then restart and its events will e +delivered to the correct Consumer. + +run_test.pl: Test #2: Consumer reconnection. +-------------------------------------------- +The Notification Service from the previous test is still running and the +saved reconnection information for both the Supplier and Consumer is still +available. + +The test script starts a Consumer configured to receive 20 events and a +Supplier configured to send twenty events. Both clients use the reconnection +information from the previous test to reconnect to the Notification Service. + +Twenty events are sent successfully, then both clients exit and the test +is complete. + +This demonstrates that a Consumer can stop then restart and reconnect. It +will continue to receive the events on the channel to which it was originally +connected. + +run_test.pl: Test #3: Saving and Restoring Topology +--------------------------------------------------- +The test script stops the Notification Server from the previous two tests and +starts a new Notification Server. It reloads the topology from the XML topology +persistence files saved during the first two tests. + +The test script starts a Consumer and a Supplier. They are configured to +receive and send respectively twenty events. The clients use the reconnection +information from the previous tests to connect to the event channel, admins, +and proxies that were reloaded from persistent topology information. +The Supplier sends and the Consumer receives 20 events. Both clients exit. + +This demonstrates that the Notification Server can save its topology, then +reload it, and the resulting topology behaves correctly when clients reconnect. + +run_test.pl: Test #4: The Reconnection Registry +----------------------------------------------- +This test starts with the Notification Service from the previous test. + +The script starts a new Consumer that expects to receive 20 events. The +Consumer reconnects to the Notification Server. +The script starts a Supplier. It is configured to send 10 events then +pause waiting for a Notification Service initiated reconnection before +sending the remaining 10 events. + +Both clients register with the Reconnection Registry to receive reconnection +callbacks. + +The test script waits for the Supplier to pause. It then kills the +Notification Service and starts a new copy. The new Notification Service +is not configured to listen at the same endpoint as the previous one did, +so the clients have no way to find the new copy directly. They must rely +on the callback received from the Reconnection Registry. + +The new Notification Service reloads its topology, including the Reconnection +Registry entries from the XML file. It sends reconnection callbacks to the +registered clients. + +Using their saved reconnection information, the clients complete the +reconnection to the new Notification Service. + +The Supplier sends the remaining 10 events then terminates. The Consumer, +having received its expected 10 events also terminates. + +This demonstrates the reconnection registry and reconnection to live clients. + +run_test.pl: Test #5: Consumer Recoverable Exception +---------------------------------------------------- +Using the Notification Service still running from the previous test, +but discarding reconnection information, a new Consumer is started. +It is configured to expect 10 events, but to throw an exception after +receiving the sixth event. After throwing the exception it expects to see +the sixth event retransmitted, then to receive the remaining four events. +A Supplier is started that sends 10 events, and then exits. +When the Consumer has received the events it expects, including the +retransmission of the sixth event, it shuts down. + +This demonstrates the Notification Service can recover from transient +communication or Consumer failures. + +Known Problems as of Feb 2004. +------------------------------ +Sequence events are not working. It is unclear whether this is a problem in +the test or in the Notification Service itself. + +Known Problems as of Mar 2004. +------------------------------ +The problem with sequence events reported previously turned out to be problems +in both the test and in the Notification Service itself. These problems +have been resolved. It is now possible to mix and match consumers and +suppliers. + +There are no new known problems. + +[----------------------------------------------------------------------------] + diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/Reconnecting.mpc b/TAO/orbsvcs/tests/Notify/Reconnecting/Reconnecting.mpc new file mode 100644 index 00000000000..75de6986a9b --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/Reconnecting.mpc @@ -0,0 +1,12 @@ +project(*Supplier): notifytest { + Source_Files { + Supplier.cpp + } +} + +project(*Consumer): notifytest { + Source_Files { + Consumer.cpp + } +} + diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.cpp b/TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.cpp new file mode 100644 index 00000000000..748ee176898 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.cpp @@ -0,0 +1,1368 @@ +//$Id$ + +#include "Supplier.h" +#include "orbsvcs/CosNotifyChannelAdminC.h" +#include "tao/debug.h" +#include "tao/PortableServer/PortableServerC.h" +#include <tao/TimeBaseC.h> +#include <ace/OS_NS_stdio.h> +#include <ace/OS_NS_strings.h> + +ACE_RCSID (Notify_Tests, Supplier_Main, "$Id$") + +static const char NOTIFY_FACTORY_NAME[] = "NotifyEventChannelFactory"; +static const char NAMING_SERVICE_NAME[] = "NameService"; + +/////////////////////////// +// StructuredPushSupplier_i + +void +StructuredPushSupplier_i::subscription_change ( + const CosNotification::EventTypeSeq & added, + const CosNotification::EventTypeSeq & removed + ACE_ENV_ARG_DECL_NOT_USED + ) + ACE_THROW_SPEC (( + CORBA::SystemException, + CosNotifyComm::InvalidEventType)) +{ + ACE_UNUSED_ARG (added); + ACE_UNUSED_ARG (removed); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Supplier StructuredPushSupplier received subscription change\n") + )); +} + + +void +StructuredPushSupplier_i::disconnect_structured_push_supplier ( + ACE_ENV_SINGLE_ARG_DECL_NOT_USED + ) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Supplier StructuredPushSupplier received disconnect\n") + )); +} + +/////////////////////////// +// SequencePushSupplier_i + +void +SequencePushSupplier_i::subscription_change ( + const CosNotification::EventTypeSeq & added, + const CosNotification::EventTypeSeq & removed + ACE_ENV_ARG_DECL_NOT_USED + ) + ACE_THROW_SPEC (( + CORBA::SystemException, + CosNotifyComm::InvalidEventType)) +{ + ACE_UNUSED_ARG (added); + ACE_UNUSED_ARG (removed); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Supplier SequencePushSupplier received subscription change\n") + )); +} + + +void +SequencePushSupplier_i::disconnect_sequence_push_supplier ( + ACE_ENV_SINGLE_ARG_DECL_NOT_USED + ) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Supplier SequencePushSupplier received disconnect\n") + )); +} + +/////////////////////////// +// AnyPushSupplier_i + +void +AnyPushSupplier_i::subscription_change ( + const CosNotification::EventTypeSeq & added, + const CosNotification::EventTypeSeq & removed + ACE_ENV_ARG_DECL_NOT_USED + ) + ACE_THROW_SPEC (( + CORBA::SystemException, + CosNotifyComm::InvalidEventType)) +{ + ACE_UNUSED_ARG (added); + ACE_UNUSED_ARG (removed); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Supplier AnyPushSupplier received subscription change\n") + )); +} + + +void +AnyPushSupplier_i::disconnect_push_supplier ( + ACE_ENV_SINGLE_ARG_DECL_NOT_USED + ) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Suppleir AnyPushSupplier received disconnect\n") + )); +} + +///////////////////////// +// ReconnectionCallback_i + +ReconnectionCallback_i::ReconnectionCallback_i (Supplier_Main & supplier_main) + : supplier_main_ (supplier_main) + , id_is_valid_ (false) + , reconnect_count_ (0) +{ +} + +size_t +ReconnectionCallback_i::reconnect_count () const +{ + return this->reconnect_count_; +} + +void +ReconnectionCallback_i::reconnect ( + CORBA::Object_ptr reconnection + ACE_ENV_ARG_DECL + ) ACE_THROW_SPEC ((CORBA::SystemException)) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier received reconnection request\n") + )); + this->ecf_ = CosNotifyChannelAdmin::EventChannelFactory::_narrow (reconnection ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + if (!CORBA::is_nil (this->ecf_.in ())) + { + this->supplier_main_.reconnect (this->ecf_.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + this->reconnect_count_ += 1; + } + else + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier reconnection request failed: wrong object type\n") + )); + } +} + +CORBA::Boolean +ReconnectionCallback_i::is_alive (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + return CORBA::Boolean (1); +} + +ReconnectionCallback_i::~ReconnectionCallback_i () +{ + // normally you would disconnect from registry here, but + // to simulate a failure, we exit without cleaning up + // if the fini method is not called. +} + + +void +ReconnectionCallback_i::fini (ACE_ENV_SINGLE_ARG_DECL) +{ + if (this->id_is_valid_) + { + NotifyExt::ReconnectionRegistry_var registry = + NotifyExt::ReconnectionRegistry::_narrow (this->ecf_.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + registry->unregister_callback (this->callback_id_ ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + this->id_is_valid_ = false; + } +} + +void +ReconnectionCallback_i::init ( + PortableServer::POA_ptr poa, + CosNotifyChannelAdmin::EventChannelFactory_ptr ecf + ACE_ENV_ARG_DECL) +{ + this->ecf_ = CosNotifyChannelAdmin::EventChannelFactory::_duplicate (ecf); + PortableServer::ObjectId_var reconnection_callback_id = + poa->activate_object (this ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + CORBA::Object_var obj = + poa->id_to_reference (reconnection_callback_id.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + NotifyExt::ReconnectionCallback_var callback = + NotifyExt::ReconnectionCallback::_narrow (obj.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + NotifyExt::ReconnectionRegistry_var registry = + NotifyExt::ReconnectionRegistry::_narrow (ecf ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + this->callback_id_ = registry->register_callback (callback.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + this->id_is_valid_ = true; +} + + + +///////////////// +// Supplier_Main + +Supplier_Main::Supplier_Main () + : verbose_ (false) + , mode_ (MODE_ANY) + , send_ (10) + , use_naming_service_ (true) + , serial_number_ (0) + , disconnect_on_exit_ (false) + , id_file_ (ACE_TEXT ("supplier.ids")) + , pause_ (0) + , reconnection_callback_ (*this) + , reconnecting_ (false) +{ +} + +Supplier_Main::~Supplier_Main () +{ +} + +int +Supplier_Main::parse_args (int argc, char *argv[]) +{ + int result = 0; + int narg = 1; + bool corba_arg = false; + while (narg < argc && result == 0) + { + int consumed = parse_single_arg (argc - narg, &argv[narg]); + if ( consumed > 0) + { + narg += consumed; + corba_arg = false; + } + else if (ACE_OS::strncmp (argv[narg], "-ORB", 4) == 0) + { + corba_arg = true; + } + else if (corba_arg) + { + // previous argument was a ORB arg. + // current argument is unrecognized + // assume the ORB eats this arg + narg += 1; + corba_arg = false; + } + else + { + ACE_OS::fprintf(stderr, "Unrecognized argument: %s\n", argv[narg]); + usage (stderr); + result = -1; + } + } + return result; +} + +int +Supplier_Main::parse_single_arg (int argc, char *argv[]) +{ + int consumed = 0; + if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-v")) == 0) + { + this->verbose_ = true; + consumed = 1; + } + else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-any")) == 0) + { + this->mode_ = MODE_ANY; + consumed = 1; + } + else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-structured")) == 0) + { + this->mode_ = MODE_STRUCTURED; + consumed = 1; + } + else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-sequence")) == 0) + { + this->mode_ = MODE_SEQUENCE; + consumed = 1; + } + else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-channel")) == 0) + { + this->channel_file_= argv[1]; + consumed = 2; + } + else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-send")) == 0 && argc > 1) + { + this->send_ = ACE_OS::atoi (argv[1]); + consumed = 2; + } + else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-pause")) == 0 && argc > 1) + { + this->pause_ = ACE_OS::atoi (argv[1]); + consumed = 2; + } + else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-serial_number")) == 0) + { + this->serial_number_= ACE_OS::atoi (argv[1]); + consumed = 2; + } + else if (ACE_OS::strcasecmp (argv[0], ACE_TEXT ("-nonamesvc")) == 0) + { + this->use_naming_service_ = false; + consumed = 1; + } + else if (ACE_OS::strcasecmp (argv[0], "-disconnect") == 0) + { + this->disconnect_on_exit_ = true; + consumed = 1; + } + + return consumed; +} + +void Supplier_Main::usage(FILE * log)const +{ + ACE_OS::fputs ( + ACE_TEXT ("usage\n") + ACE_TEXT (" -channel filename Where to find a channel number.\n") + ACE_TEXT (" -any or -structured or -sequence\n") + ACE_TEXT (" What type of event to send (pick one, default is -any)\n") + ACE_TEXT (" -send n How many events of each type to send.\n") + ACE_TEXT (" -pause n Pause after sending n events. Write to file \"Supplier.paused\"\n") + ACE_TEXT (" -serial_number n What serial number to start with.\n") + ACE_TEXT (" -v Verbose output.\n") + ACE_TEXT (" -disconnect Disconnect from channel on exit (prevents reconnect.) \n") + ACE_TEXT (" -nonamesvc Don't use the name service to find EventChannelFactory\n") + , log); +} + +int Supplier_Main::init (int argc, char *argv[] ACE_ENV_ARG_DECL) +{ + this->orb_ = CORBA::ORB_init(argc, argv, "" ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + if (0 != this->parse_args(argc, argv)) + { + return -1; + } + + CORBA::Object_ptr poa_object = + this->orb_->resolve_initial_references("RootPOA" + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + if (CORBA::is_nil (poa_object)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT (" (%P|%t) Unable to initialize the POA.\n"))); + return -1; + } + + this->root_poa_ = + PortableServer::POA::_narrow (poa_object ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + PortableServer::POAManager_var poa_manager = + root_poa_->the_POAManager (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + poa_manager->activate (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + if (this->use_naming_service_ ) + { + this->find_notify_factory (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + } + else + { + int ok = resolve_notify_factory (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + if (!ok) + { + return -1; + } + } + + this->reconnecting_ = load_ids (); + + init_event_channel (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + init_supplier_admin (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + switch (this->mode_) + { + case MODE_STRUCTURED: + { + init_structured_proxy_consumer (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + break; + } + case MODE_SEQUENCE: + { + init_sequence_proxy_consumer (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + break; + } + case MODE_ANY: + { + + init_any_proxy_consumer (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + break; + } + default: + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Supplier: Unknown event push mode.\n") + )); + break; + } + } + this->reconnection_callback_.init ( + this->root_poa_.in (), + this->ecf_.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + save_ids (); + return 0; +} +void +Supplier_Main::save_ids() +{ + FILE *idf = + ACE_OS::fopen (this->id_file_.c_str (), "w"); + + if (idf != 0) + { + int endflag = 12345; + int imode = ACE_static_cast (int, this->mode_); + ACE_OS::fprintf (idf, + "%d,%d,%d,%d,%d,%d,%d,\n", + imode, + ec_id_, + sa_id_, + structured_proxy_id_, + sequence_proxy_id_, + any_proxy_id_, + endflag); + ACE_OS::fclose (idf); + } +} + +bool +Supplier_Main::load_ids() +{ + bool ok = false; + FILE *idf = + ACE_OS::fopen (this->id_file_.c_str (), "w"); + + if (idf != 0) + { + int field = 0; + + char buffer[100]; + ACE_OS::fgets (buffer, sizeof(buffer), idf); + ACE_OS::fclose (idf); + char * pb = buffer; + while (*pb != 0) + { + char * eb = ACE_OS::strchr (pb, ','); + char * nb = eb + 1; + if (eb == 0) + { + eb = pb + ACE_OS::strlen (pb); + nb = eb; + } + else + { + *eb = 0; + } + if (pb < eb) + { + int value = ACE_OS::atoi(pb); + switch (field) + { + case 1: + this->mode_ = static_cast<Mode_T> (value); + break; + case 2: + this->ec_id_ = value; + break; + case 3: + this->sa_id_ = value; + break; + case 4: + this->structured_proxy_id_ = value; + break; + case 5: + this->sequence_proxy_id_ = value; + break; + case 6: + this->any_proxy_id_ = value; + break; + case 7: + ok = value == 12345; + break; + default: + ACE_OS::fprintf (stderr, ACE_TEXT ("Warning: too many fields in saved id file.\n")); + ok = false; + break; + } + } + pb = nb; + } + } + return ok; +} + +void +Supplier_Main::reconnect ( + CosNotifyChannelAdmin::EventChannelFactory_ptr dest_factory + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + this->ecf_ = CosNotifyChannelAdmin::EventChannelFactory::_duplicate (dest_factory); + this->reconnecting_ = true; + init_event_channel (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + + init_supplier_admin (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + + switch (this->mode_) + { + case MODE_STRUCTURED: + { + init_structured_proxy_consumer (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + break; + } + case MODE_SEQUENCE: + { + init_sequence_proxy_consumer (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + break; + } + case MODE_ANY: + { + init_any_proxy_consumer (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK; + break; + } + } +} + + +int +Supplier_Main::resolve_naming_service (ACE_ENV_SINGLE_ARG_DECL) +{ + // ignore redundant calls + if (CORBA::is_nil (this->naming_context_.in ())) + { + CORBA::Object_var naming_obj = + this->orb_->resolve_initial_references (NAMING_SERVICE_NAME + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + + this->naming_context_ = + CosNaming::NamingContext::_narrow (naming_obj.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + } + + return !CORBA::is_nil (this->naming_context_.in ()); +} + +int +Supplier_Main::find_notify_factory (ACE_ENV_SINGLE_ARG_DECL) +{ + int status = this->resolve_naming_service (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (0); + if (status) + { + CosNaming::Name name (1); + name.length (1); + name[0].id = CORBA::string_dup (NOTIFY_FACTORY_NAME); + + CORBA::Object_var obj = + this->naming_context_->resolve (name + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + + this->ecf_ = + CosNotifyChannelAdmin::EventChannelFactory::_narrow ( + obj.in () + ACE_ENV_ARG_PARAMETER + ); + ACE_CHECK_RETURN(0); + } + return ! CORBA::is_nil (this->ecf_.in ()); +} + +int +Supplier_Main::resolve_notify_factory (ACE_ENV_SINGLE_ARG_DECL) +{ + CORBA::Object_var factory_obj = + this->orb_->resolve_initial_references (NOTIFY_FACTORY_NAME + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + + this->ecf_ = + CosNotifyChannelAdmin::EventChannelFactory::_narrow ( + factory_obj.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN(0); + return ! CORBA::is_nil (this->ecf_.in ()); +} + +void +Supplier_Main::init_event_channel (ACE_ENV_SINGLE_ARG_DECL) +{ + bool ok = false; + if (this->reconnecting_) + { + ACE_TRY_NEW_ENV + { + this->ec_ = this->ecf_->get_event_channel ( + this->ec_id_ + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + ok = ! CORBA::is_nil (this->ec_.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier: Reconnect to event channel %d\n"), + ACE_static_cast (int, this->ec_id_) + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + + if (!ok && this->channel_file_.length () > 0) + { + FILE * chf = ACE_OS::fopen (this->channel_file_.c_str (), "r"); + if (chf != 0) + { + char buffer[100]; + ACE_OS::fgets (buffer, sizeof(buffer), chf); + ACE_OS::fclose (chf); + this->ec_id_ = ACE_OS::atoi (buffer); + + ACE_DECLARE_NEW_ENV; + ACE_TRY_EX (unique_label_1) + { + this->ec_ = this->ecf_->get_event_channel ( + this->ec_id_ + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK_EX (unique_label_1) + ok = ! CORBA::is_nil (this->ec_.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) supplier: Connect to Consumer's event channel %d\n"), + ACE_static_cast (int, this->ec_id_) + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + } + + if (!ok) + { + CosNotification::QoSProperties qosprops(7); + qosprops.length(7); + + CORBA::ULong i = 0; +#ifdef DISABLE_PROPERITIES_TODO + qosprops[i].name = CORBA::string_dup(CosNotification::EventReliability); + qosprops[i++].value <<= CosNotification::Persistent; + qosprops[i].name = CORBA::string_dup(CosNotification::ConnectionReliability); + qosprops[i++].value <<= CosNotification::Persistent; // Required, or we won't persist much + qosprops[i].name = CORBA::string_dup(CosNotification::Priority); + qosprops[i++].value <<= CosNotification::HighestPriority; + qosprops[i].name = CORBA::string_dup(CosNotification::Timeout); + qosprops[i++].value <<= (TimeBase::TimeT) 42 * 1000000; // 4.2s + qosprops[i].name = CORBA::string_dup(CosNotification::StopTimeSupported); + qosprops[i++].value <<= CORBA::Any::from_boolean(1); + qosprops[i].name = CORBA::string_dup(CosNotification::MaximumBatchSize); + qosprops[i++].value <<= (CORBA::Long) 2; + qosprops[i].name = CORBA::string_dup(CosNotification::PacingInterval); + qosprops[i++].value <<= (TimeBase::TimeT) 50 * 10000; // 50ms +#endif + qosprops.length(i); + + CosNotification::AdminProperties adminprops(4); + adminprops.length(4); + i = 0; +#ifdef DISABLE_PROPERTIES_TODO + adminprops[i].name = CORBA::string_dup(CosNotification::MaxQueueLength); + adminprops[i++].value <<= (CORBA::Long) 1234; + adminprops[i].name = CORBA::string_dup(CosNotification::MaxConsumers); + adminprops[i++].value <<= (CORBA::Long) 1000; + adminprops[i].name = CORBA::string_dup(CosNotification::MaxSuppliers); + adminprops[i++].value <<= (CORBA::Long) 1000; + adminprops[i].name = CORBA::string_dup(CosNotification::RejectNewEvents); + adminprops[i++].value <<= CORBA::Any::from_boolean(1); +#endif + adminprops.length(i); + + ec_ = this->ecf_->create_channel ( + qosprops, + adminprops, + this->ec_id_ + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + ok = ! CORBA::is_nil (ec_.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier: Create event channel %d\n"), + ACE_static_cast (int, this->ec_id_) + )); + } + } +} + +CosNotifyChannelAdmin::AdminID default_admin_id = ACE_static_cast (CosNotifyChannelAdmin::AdminID, -1); + +void +Supplier_Main::init_supplier_admin (ACE_ENV_SINGLE_ARG_DECL) +{ + bool ok = false; + if (this->reconnecting_ && this->sa_id_ != default_admin_id) + { + ACE_TRY_EX(ONE) + { + this->sa_ = this->ec_->get_supplieradmin( + this->sa_id_ + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK_EX(ONE); + ok = ! CORBA::is_nil (this->sa_.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier: Reconnect to supplier admin %d\n"), + ACE_static_cast (int, this->sa_id_) + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + + if (!ok) + { + ACE_TRY_EX(TWO) + { + this->sa_ = this->ec_->default_supplier_admin (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK_EX(TWO); + ok = ! CORBA::is_nil (this->sa_.in ()); + this->sa_id_ = default_admin_id; + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier: Using default supplier admin\n") + )); + } + else if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier: No default supplier admin\n") + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + + if (!ok) + { + this->sa_ = this->ec_->new_for_suppliers( + CosNotifyChannelAdmin::OR_OP, + this->sa_id_ + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + ok = ! CORBA::is_nil (this->sa_.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier: Create new supplier admin %d\n"), + ACE_static_cast (int, this->sa_id_) + )); + } + } +} + +void +Supplier_Main::init_structured_proxy_consumer (ACE_ENV_SINGLE_ARG_DECL) +{ + bool ok = false; + CosNotifyChannelAdmin::ProxyConsumer_var proxy; + if (this->reconnecting_) + { + ACE_TRY_NEW_ENV + { + proxy = this->sa_->get_proxy_consumer ( + this->structured_proxy_id_ + ACE_ENV_ARG_PARAMETER + ); + ACE_TRY_CHECK; + ok = ! CORBA::is_nil (proxy.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier: Reconnect to proxy supplier %d\n"), + ACE_static_cast (int, this->structured_proxy_id_) + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + + if (!ok) + { + proxy = this->sa_->obtain_notification_push_consumer( + CosNotifyChannelAdmin::STRUCTURED_EVENT, + this->structured_proxy_id_ + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + ok = ! CORBA::is_nil (proxy.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier: Create new proxy %d\n"), + ACE_static_cast (int, this->structured_proxy_id_) + )); + } + } + this->structured_proxy_push_consumer_ = + CosNotifyChannelAdmin::StructuredProxyPushConsumer::_narrow(proxy.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + if (CORBA::is_nil (this->structured_proxy_push_consumer_.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) init_structured_proxy_consumer received nil ProxyConsumer\n") + )); + ACE_THROW (CORBA::OBJECT_NOT_EXIST ()); + } + if (CORBA::is_nil (this->structured_push_supplier_ref_.in ())) + { + PortableServer::ObjectId_var push_supplier_id = + this->root_poa_->activate_object ( + &(this->structured_push_supplier_) ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + CORBA::Object_var obj = + this->root_poa_->id_to_reference (push_supplier_id.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + this->structured_push_supplier_ref_ = + CosNotifyComm::StructuredPushSupplier::_narrow (obj.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + if (CORBA::is_nil (structured_push_supplier_ref_.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Supplier: Received wrong type of push consumer proxy %d\n"), + ACE_static_cast (int, this->structured_proxy_id_) + )); + + ACE_THROW (CORBA::UNKNOWN()); + } + + this->structured_proxy_push_consumer_->connect_structured_push_supplier ( + structured_push_supplier_ref_.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; +} + +void +Supplier_Main::init_sequence_proxy_consumer (ACE_ENV_SINGLE_ARG_DECL) +{ + bool ok = false; + CosNotifyChannelAdmin::ProxyConsumer_var proxy; + if (this->reconnecting_) + { + ACE_TRY_NEW_ENV + { + proxy = this->sa_->get_proxy_consumer( + this->sequence_proxy_id_ + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + ok = ! CORBA::is_nil (proxy.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier: Reconnect to proxy %d\n"), + ACE_static_cast (int, this->sequence_proxy_id_) + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + + if (!ok) + { + proxy = this->sa_->obtain_notification_push_consumer( + CosNotifyChannelAdmin::SEQUENCE_EVENT, + this->sequence_proxy_id_ + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + ok = ! CORBA::is_nil (proxy.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier: Create new proxy %d\n"), + ACE_static_cast (int, this->sequence_proxy_id_) + )); + } + } + this->sequence_proxy_push_consumer_ = + CosNotifyChannelAdmin::SequenceProxyPushConsumer::_narrow(proxy.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + if (CORBA::is_nil (this->sequence_proxy_push_consumer_.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Supplier: Received wrong type of push consumer proxy %d\n"), + ACE_static_cast (int, this->sequence_proxy_id_) + )); + ACE_THROW (CORBA::UNKNOWN()); + } + + if (CORBA::is_nil (this->sequence_push_supplier_ref_.in ())) + { + PortableServer::ObjectId_var push_supplier_id = + this->root_poa_->activate_object ( + &(this->sequence_push_supplier_) ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + CORBA::Object_var obj = + this->root_poa_->id_to_reference (push_supplier_id.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + this->sequence_push_supplier_ref_ = + CosNotifyComm::SequencePushSupplier::_narrow (obj.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + if (CORBA::is_nil (sequence_push_supplier_ref_.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Supplier: Received wrong type of push consumer proxy %d\n"), + ACE_static_cast (int, this->sequence_proxy_id_) + )); + ACE_THROW (CORBA::UNKNOWN()); + } + + this->sequence_proxy_push_consumer_->connect_sequence_push_supplier ( + sequence_push_supplier_ref_.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; +} + +void +Supplier_Main::init_any_proxy_consumer (ACE_ENV_SINGLE_ARG_DECL) +{ + bool ok = false; + CosNotifyChannelAdmin::ProxyConsumer_var proxy; + if (this->reconnecting_) + { + ACE_TRY_NEW_ENV + { + proxy = this->sa_->get_proxy_consumer( + this->any_proxy_id_ + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + ok = ! CORBA::is_nil (proxy.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier: Reconnect to proxy %d\n"), + ACE_static_cast (int, this->any_proxy_id_) + )); + } + } + ACE_CATCHALL + { + } + ACE_ENDTRY; + } + + if (!ok) + { + proxy = this->sa_->obtain_notification_push_consumer( + CosNotifyChannelAdmin::ANY_EVENT, + this->any_proxy_id_ + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + ok = ! CORBA::is_nil (proxy.in ()); + if (ok && this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier: Create new proxy\n"), + ACE_static_cast (int, this->any_proxy_id_) + )); + } + } + this->any_proxy_push_consumer_ = + CosNotifyChannelAdmin::ProxyPushConsumer::_narrow(proxy.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + if (CORBA::is_nil (this->any_proxy_push_consumer_.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Supplier: Received wrong type of push consumer proxy %d\n"), + ACE_static_cast (int, this->any_proxy_id_) + )); + ACE_THROW (CORBA::UNKNOWN()); + } + + if (CORBA::is_nil (this->any_push_supplier_ref_.in ())) + { + PortableServer::ObjectId_var push_supplier_id = + this->root_poa_->activate_object ( + &(this->any_push_supplier_) ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + CORBA::Object_var obj = + this->root_poa_->id_to_reference (push_supplier_id.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + + this->any_push_supplier_ref_ = + CosNotifyComm::PushSupplier::_narrow (obj.in () ACE_ENV_ARG_PARAMETER); + ACE_CHECK; + } + if (CORBA::is_nil (any_push_supplier_ref_.in ())) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Supplier: Received wrong type of push consumer proxy %d\n"), + ACE_static_cast (int, this->sequence_proxy_id_) + )); + ACE_THROW (CORBA::UNKNOWN()); + } + + this->any_proxy_push_consumer_->connect_any_push_supplier ( + any_push_supplier_ref_.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; +} + +int Supplier_Main::fini (ACE_ENV_SINGLE_ARG_DECL) +{ + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) supplier::fini\n") + )); + if (this->disconnect_on_exit_) + { + this->reconnection_callback_.fini (ACE_ENV_SINGLE_ARG_PARAMETER); + if (!CORBA::is_nil (this->structured_proxy_push_consumer_.in ())) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Disconnecting structured\n") + )); + } + this->structured_proxy_push_consumer_->disconnect_structured_push_consumer (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-4); + } + if (!CORBA::is_nil (this->sequence_proxy_push_consumer_.in ())) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Disconnecting sequence\n") + )); + } + this->sequence_proxy_push_consumer_->disconnect_sequence_push_consumer (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-4); + } + if (!CORBA::is_nil (this->any_proxy_push_consumer_.in ())) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Disconnecting any\n") + )); + } + this->any_proxy_push_consumer_->disconnect_push_consumer (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-4); + } + if (!CORBA::is_nil (this->sa_.in ()) && this->sa_id_ != default_admin_id) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) destroy admin %d\n"), + ACE_static_cast(int, this->sa_id_) + )); + } + this->sa_->destroy(); + } + } + this->orb_->shutdown (); + return 0; +} + +void Supplier_Main::send_structured_event (ACE_ENV_SINGLE_ARG_DECL) +{ + CosNotification::StructuredEvent event; + + // EventHeader. + + // FixedEventHeader. + // EventType. + // string. + event.header.fixed_header.event_type.domain_name = CORBA::string_dup("*"); + // string + event.header.fixed_header.event_type.type_name = CORBA::string_dup("*"); + // string + event.header.fixed_header.event_name = CORBA::string_dup("reconnect_test"); + + // OptionalHeaderFields. + // PropertySeq. + // sequence<Property>: string name, any value + CosNotification::PropertySeq& qos = event.header.variable_header; + qos.length (2); + qos[0].name = CORBA::string_dup (CosNotification::Priority); + qos[0].value <<= CosNotification::LowestPriority; + qos[1].name = CORBA::string_dup (CosNotification::EventReliability); + qos[1].value <<= CosNotification::Persistent; + + // FilterableEventBody + // PropertySeq + // sequence<Property>: string name, any value + event.filterable_data.length (1); + event.filterable_data[0].name = CORBA::string_dup("serial_number"); + event.filterable_data[0].value <<= CORBA::ULong ( this->serial_number_); + + // any + event.remainder_of_body <<= CORBA::ULong ( this->serial_number_); + + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Supplier push structured event %d\n"), + ACE_static_cast (int, serial_number_) + )); + } + + this->structured_proxy_push_consumer_->push_structured_event (event + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; +} + +void Supplier_Main::send_sequence_event (ACE_ENV_SINGLE_ARG_DECL) +{ + CosNotification::EventBatch event_batch(1); + event_batch.length (1); + CosNotification::StructuredEvent & event = event_batch[0]; + + // EventHeader. + + // FixedEventHeader. + // EventType. + // string. + event.header.fixed_header.event_type.domain_name = CORBA::string_dup("*"); + // string + event.header.fixed_header.event_type.type_name = CORBA::string_dup("*"); + // string + event.header.fixed_header.event_name = CORBA::string_dup("reconnect_test"); + + // OptionalHeaderFields. + // PropertySeq. + // sequence<Property>: string name, any value + CosNotification::PropertySeq& qos = event.header.variable_header; + qos.length (2); + qos[0].name = CORBA::string_dup (CosNotification::Priority); + qos[0].value <<= CosNotification::LowestPriority; + qos[1].name = CORBA::string_dup (CosNotification::EventReliability); + qos[1].value <<= CosNotification::Persistent; + + // FilterableEventBody + // PropertySeq + // sequence<Property>: string name, any value + event.filterable_data.length (1); + event.filterable_data[0].name = CORBA::string_dup("serial_number"); + event.filterable_data[0].value <<= CORBA::ULong ( this->serial_number_); + + // any + event.remainder_of_body <<= CORBA::ULong ( this->serial_number_); + + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Supplier push sequence events %d\n"), + ACE_static_cast (int, this->serial_number_) + )); + } + + this->sequence_proxy_push_consumer_->push_structured_events (event_batch + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; +} + +void Supplier_Main::send_any_event (ACE_ENV_SINGLE_ARG_DECL) +{ + CORBA::Any event; + event <<= CORBA::ULong (this->serial_number_); + + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Supplier push any event %d\n"), + ACE_static_cast (int, this->serial_number_) + )); + } + + this->any_proxy_push_consumer_->push (event + ACE_ENV_ARG_PARAMETER); + ACE_CHECK; +} + +int Supplier_Main::run (ACE_ENV_SINGLE_ARG_DECL) +{ + int result = 0; + bool paused = false; + size_t reconnections = 0; + + size_t send = 0; + while ( send < this->send_) + { + // keep the orb alive -- listenting for reconnect + if (this->orb_->work_pending ()) + { + this->orb_->perform_work (); + } + + if (this->pause_ != 0 && send == this->pause_) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier paused after %d events\n"), + ACE_static_cast (int, this->pause_) + )); + } + reconnections = this->reconnection_callback_.reconnect_count (); + FILE * pause_file = ACE_OS::fopen ("Supplier.paused", "w"); + if (pause_file != 0) + { + ACE_OS::fputs (ACE_TEXT ("paused\n"), pause_file); + ACE_OS::fclose (pause_file); + } + paused = true; + this->pause_ = 0; + } + if (paused) + { + if (this->reconnection_callback_.reconnect_count () != reconnections) + { + if (this->verbose_) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) Supplier no longer paused. Next s# %d\n"), + ACE_static_cast (int, this->serial_number_) + )); + } + paused = false; + } + } + + if (!paused) + { + switch (this->mode_) + { + case MODE_STRUCTURED: + { + send_structured_event (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + break; + } + case MODE_SEQUENCE: + { + send_sequence_event (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + break; + } + case MODE_ANY: + { + send_any_event (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + break; + } + } + this->serial_number_ += 1; + send += 1; + } + } + return result; +} + + +int +main (int argc, char *argv[]) +{ + int result = -1; + Supplier_Main app; + ACE_TRY_NEW_ENV + { + result = app.init(argc, argv ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK + + if (result == 0) + { + result = app.run (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + } + if (result == 0) + { + app.fini (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + } + } + ACE_CATCHANY + { + ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, + "Supplier::main\t\n"); + result = -1; + } + ACE_ENDTRY; + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P,%t) Supplier exits: code %d\n"), + result + )); + return result; +} + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.h b/TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.h new file mode 100644 index 00000000000..f429cf7892c --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/Supplier.h @@ -0,0 +1,209 @@ +/* -*- C++ -*- */ +// $Id$ +// ========================================================================== +// +// = FILENAME +// Supplier.h +// +// = DESCRIPTION +// Test Supplier reconnect to existing channel/admin/proxy Notification Service +// +// = AUTHOR +// Dale Wilson <wilson_d@ociweb.com> +// +// ========================================================================== + +#ifndef RECONNECTNG_SUPPLIER_H +#define RECONNECTNG_SUPPLIER_H + +#include "orbsvcs/CosNotifyChannelAdminC.h" +#include "orbsvcs/CosNamingC.h" +#include "orbsvcs/NotifyExtS.h" +#include <ace/SString.h> + +class Supplier_Main; + +class StructuredPushSupplier_i : public virtual POA_CosNotifyComm::StructuredPushSupplier +{ + virtual void subscription_change ( + const CosNotification::EventTypeSeq & added, + const CosNotification::EventTypeSeq & removed + ACE_ENV_ARG_DECL + ) + ACE_THROW_SPEC (( + CORBA::SystemException, + CosNotifyComm::InvalidEventType)); + + virtual void disconnect_structured_push_supplier ( + ACE_ENV_SINGLE_ARG_DECL + ) + ACE_THROW_SPEC ((CORBA::SystemException)); +}; + +class SequencePushSupplier_i : public virtual POA_CosNotifyComm::SequencePushSupplier +{ + virtual void subscription_change ( + const CosNotification::EventTypeSeq & added, + const CosNotification::EventTypeSeq & removed + ACE_ENV_ARG_DECL + ) + ACE_THROW_SPEC (( + CORBA::SystemException, + CosNotifyComm::InvalidEventType)); + + virtual void disconnect_sequence_push_supplier ( + ACE_ENV_SINGLE_ARG_DECL + ) + ACE_THROW_SPEC ((CORBA::SystemException)); +}; + +class AnyPushSupplier_i : public virtual POA_CosNotifyComm::PushSupplier +{ + virtual void subscription_change ( + const CosNotification::EventTypeSeq & added, + const CosNotification::EventTypeSeq & removed + ACE_ENV_ARG_DECL + ) + ACE_THROW_SPEC (( + CORBA::SystemException, + CosNotifyComm::InvalidEventType)); + + virtual void disconnect_push_supplier ( + ACE_ENV_SINGLE_ARG_DECL + ) + ACE_THROW_SPEC ((CORBA::SystemException)); +}; + +class ReconnectionCallback_i : public virtual POA_NotifyExt::ReconnectionCallback +{ +public: + ReconnectionCallback_i (Supplier_Main & supplier_main); + + virtual ~ReconnectionCallback_i (); + + void init ( + PortableServer::POA_ptr poa, + CosNotifyChannelAdmin::EventChannelFactory_ptr ecf_ + ACE_ENV_ARG_DECL); + + void fini (ACE_ENV_SINGLE_ARG_DECL); + + size_t reconnect_count () const; + + virtual void reconnect ( + CORBA::Object_ptr reconnection + ACE_ENV_ARG_DECL + ) ACE_THROW_SPEC ((CORBA::SystemException)); + + virtual CORBA::Boolean is_alive (ACE_ENV_SINGLE_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + +private: + Supplier_Main & supplier_main_; + bool id_is_valid_; + NotifyExt::ReconnectionRegistry::ReconnectionID callback_id_; + CosNotifyChannelAdmin::EventChannelFactory_var ecf_; + size_t reconnect_count_; +}; + +class Supplier_Main +{ + public: + Supplier_Main (); + ~Supplier_Main (); + + int parse_args (int argc, char *argv[]); + int parse_single_arg (int argc, char *argv[]); + + int init (int argc, char *argv[] ACE_ENV_ARG_DECL); + int run (ACE_ENV_SINGLE_ARG_DECL); + int fini (ACE_ENV_SINGLE_ARG_DECL); + void usage (FILE * log) const; + + void reconnect ( + CosNotifyChannelAdmin::EventChannelFactory_ptr dest_factory + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + + private: + /// Find naming service. + int resolve_naming_service (ACE_ENV_SINGLE_ARG_DECL); + + /// Resolve the Notify factory from the Naming service. + int find_notify_factory (ACE_ENV_SINGLE_ARG_DECL); + + /// Resolve the Notify factory using resolve_initial_reference ("NotifyEventChannelFactory") + int resolve_notify_factory (ACE_ENV_SINGLE_ARG_DECL); + + void init_event_channel (ACE_ENV_SINGLE_ARG_DECL); + void init_supplier_admin (ACE_ENV_SINGLE_ARG_DECL); + void init_structured_proxy_consumer (ACE_ENV_SINGLE_ARG_DECL); + void init_sequence_proxy_consumer (ACE_ENV_SINGLE_ARG_DECL); + void init_any_proxy_consumer (ACE_ENV_SINGLE_ARG_DECL); + + /// send events. + void send_structured_event (ACE_ENV_SINGLE_ARG_DECL); + void send_sequence_event (ACE_ENV_SINGLE_ARG_DECL); + void send_any_event (ACE_ENV_SINGLE_ARG_DECL); + + void save_ids(); + bool load_ids(); + + //////////////////// + // forbidden methods + private: + Supplier_Main (const Supplier_Main & rhs); + Supplier_Main & operator = (const Supplier_Main & rhs); + + //////////////// + // Data members + private: + + // set by command line parameters + bool verbose_; // -v make a glorious noise + enum Mode_T { + MODE_ANY, + MODE_STRUCTURED, + MODE_SEQUENCE} mode_; // -any, -structured, or -sequence + ACE_CString channel_file_; // -channel filename + size_t send_; // -send n + bool use_naming_service_; // -nonamesvc + size_t serial_number_; // -serial_number + bool disconnect_on_exit_; // -disconnect + ACE_CString id_file_; // -ids + size_t pause_; // -pause n (pause after sending n messages) + CORBA::ORB_var orb_; + PortableServer::POA_var root_poa_; + CosNaming::NamingContext_var naming_context_; + CosNotifyChannelAdmin::EventChannelFactory_var ecf_; + + CosNotifyChannelAdmin::EventChannel_var ec_; + CosNotifyChannelAdmin::ChannelID ec_id_; + + CosNotifyChannelAdmin::SupplierAdmin_var sa_; + CosNotifyChannelAdmin::AdminID sa_id_; + + CosNotifyChannelAdmin::StructuredProxyPushConsumer_var structured_proxy_push_consumer_; + CosNotifyChannelAdmin::ProxyID structured_proxy_id_; + StructuredPushSupplier_i structured_push_supplier_; + CosNotifyComm::StructuredPushSupplier_var structured_push_supplier_ref_; + + + CosNotifyChannelAdmin::SequenceProxyPushConsumer_var sequence_proxy_push_consumer_; + CosNotifyChannelAdmin::ProxyID sequence_proxy_id_; + SequencePushSupplier_i sequence_push_supplier_; + CosNotifyComm::SequencePushSupplier_var sequence_push_supplier_ref_; + + CosNotifyChannelAdmin::ProxyPushConsumer_var any_proxy_push_consumer_; + CosNotifyChannelAdmin::ProxyID any_proxy_id_; + AnyPushSupplier_i any_push_supplier_; + CosNotifyComm::PushSupplier_var any_push_supplier_ref_; + + ReconnectionCallback_i reconnection_callback_; + + bool reconnecting_; +}; + + + +#endif /* RECONNECTNG_SUPPLIER_H */ diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/event.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/event.conf new file mode 100644 index 00000000000..04992b13665 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/event.conf @@ -0,0 +1,6 @@ + +static CosNotify_Service "-AllowReconnect" + +# This should fail because event perstence requires topology persistence + +dynamic Event_Persistence Service_Object* TAO_CosNotification:_make_Standard_Event_Persistence() "-v -file_path ./event_persist.db"
\ No newline at end of file diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt.conf new file mode 100644 index 00000000000..bb4c2d1f954 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt.conf @@ -0,0 +1,10 @@ + +## -DispatchingThreads N - creates a thread pool for dispatching and consumer side filter eval +## -SourceThreads M - creates a thread pool for lookup and supplier side filter eval + +## This prevents worker threads from joining the tp reactor +##static Client_Strategy_Factory "-ORBClientConnectionHandler rw" + +static CosNotify_Service "-DispatchingThreads 2 -SourceThreads 2 -AllowReconnect" + + diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_both.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_both.conf new file mode 100644 index 00000000000..00559411451 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_both.conf @@ -0,0 +1,5 @@ +static CosNotify_Service "-DispatchingThreads 2 -SourceThreads 2 -AllowReconnect" + +dynamic Topology_Factory Service_Object* TAO_CosNotification_persist:_make_XML_Topology_Factory() "-base_path ./reconnect_test" +dynamic Event_Persistence Service_Object* TAO_CosNotification_persist:_make_Standard_Event_Persistence() "-file_path ./event_persist.db" + diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_topo.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_topo.conf new file mode 100644 index 00000000000..0ab2672941d --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_mt_topo.conf @@ -0,0 +1,3 @@ +static CosNotify_Service "-DispatchingThreads 2 -SourceThreads 2 -AllowReconnect" +dynamic Topology_Factory Service_Object* TAO_CosNotification_persist:_make_XML_Topology_Factory() "-base_path ./reconnect_test" + diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st.conf new file mode 100644 index 00000000000..902cc095284 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st.conf @@ -0,0 +1,4 @@ + +static CosNotify_Service "-AllowReconnect" + + diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_both.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_both.conf new file mode 100644 index 00000000000..5496d663e82 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_both.conf @@ -0,0 +1,4 @@ +static CosNotify_Service "-AllowReconnect" + +dynamic Topology_Factory Service_Object* TAO_CosNotification_persist:_make_XML_Topology_Factory() "-v -base_path ./reconnect_test" +dynamic Event_Persistence Service_Object* TAO_CosNotification_persist:_make_Standard_Event_Persistence() "-v -file_path ./event_persist.db" diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_topo.conf b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_topo.conf new file mode 100644 index 00000000000..d6f099b3d24 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/ns_st_topo.conf @@ -0,0 +1,2 @@ +static CosNotify_Service "-AllowReconnect" +dynamic Topology_Factory Service_Object* TAO_CosNotification_persist:_make_XML_Topology_Factory() "-v -base_path ./reconnect_test" diff --git a/TAO/orbsvcs/tests/Notify/Reconnecting/run_test.pl b/TAO/orbsvcs/tests/Notify/Reconnecting/run_test.pl new file mode 100755 index 00000000000..c878e97f8c4 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/Reconnecting/run_test.pl @@ -0,0 +1,386 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "../../../../../bin"; +use PerlACE::Run_Test; + +my($eventType) = "-any"; # your choice of -any -structured or -sequence + +my($ACE_ROOT) = $ENV{ACE_ROOT}; +my($TAO_ROOT) = "$ACE_ROOT/TAO"; + +my($notify_port) = "9889"; + +#file used to detect notification service startup +my($notify_ior) = PerlACE::LocalFile("notify.ior"); +#hard coded file name in Consumer.cpp (for now) +my($consumer_ids) = PerlACE::LocalFile("consumer.ids"); +#hard coded file name in Supplier.cpp (for now) +my($supplier_ids) = PerlACE::LocalFile("supplier.ids"); +#file used to communicate channel # from consumer to supplier +my($channel_id) = PerlACE::LocalFile("channel_id"); +#file names comes from svc.conf (+.xml & .000) +my($save_xml) = PerlACE::LocalFile("./reconnect_test.xml"); +my($save_000) = PerlACE::LocalFile("./reconnect_test.000"); +my($eventpersist) = PerlACE::LocalFile("./event_persist.db"); +# hardcode filename written by the Supplier when it pauses. +my($supplier_pause) = PerlACE::LocalFile("Supplier.paused"); + +my($verbose) = ""; + +my $svcconf = "ns_st_topo.conf"; + +# Process command line arguments +foreach $i (@ARGV) { + if ($i eq "-any") { + $eventType = "-any"; + } + elsif ($i eq "-str" or $i eq "-structured") { + $eventType = "-structured"; + } + elsif ($i eq "-seq" or $i eq "-sequence") { + $eventType = "-sequence"; + } + elsif ($i eq "-mt") { + $svcconf = "ns_mt_topo.conf"; + } + elsif ($i eq "-v" or $i eq "-verbose") { + $verbose = "-v"; + } + else { + print "TEST SCRIPT: unknown: $i\n"; + print "TEST SCRIPT: usage: [-any|-str|-seq] -mt -v\n"; + exit -4; + } +} + +my($client_args) = " $eventType $verbose -NoNameSvc -ORBInitRef NotifyEventChannelFactory=corbaloc::localhost:$notify_port/NotifyEventChannelFactory "; +my($ns_args) = " -NoNameSvc -Boot -ORBSvcConf $svcconf -IORoutput $notify_ior -ORBEndpoint iiop://:$notify_port "; +#my($ns_args_hidden) = " -NoNameSvc -Boot -ORBSvcConf $svcconf -IORoutput $notify_ior"; +# nuke the topology save files so we start clean +unlink $save_xml; +unlink $save_000; +unlink $eventpersist; +unlink $notify_ior; + + +##define the processes first +my($NS) = new PerlACE::Process("$TAO_ROOT/orbsvcs/Notify_Service/Notify_Service"); +my($CON) = new PerlACE::Process("./Consumer"); +my($SUP) = new PerlACE::Process("./Supplier"); + +if ($verbose eq "-v") {print "TEST SCRIPT: Starting Notify Service on port $notify_port\n";} +$NS->Arguments($ns_args); +if ($verbose eq "-v") {print "TEST SCRIPT: " . $NS->CommandLine . "\n";} +$NS->Spawn(); + +# the ior file is only used to wait for the service to start +if (PerlACE::waitforfile_timed ($notify_ior, 10) == -1) { + print STDERR "ERROR: Timed out waiting for $notify_ior\n"; + $NS->Kill (); + exit 1; +} +# be sure consumer doesn't try to reconnect the first time +unlink $consumer_ids; +# don't use previous channel id +unlink $channel_id; + +# start the consumer, +# write the channel number to channel.id for use by Supplier +# expect to receive 20 events of type any +# +$CON->Arguments("-channel $channel_id -expect 20 $client_args"); +if ($verbose eq "-v") {print "TEST SCRIPT: " . $CON->CommandLine . "\n";} +$CON->Spawn(); + +# wait for the channel number file +if (PerlACE::waitforfile_timed ($channel_id, 10) == -1) { + print STDERR "ERROR: Timed out waiting for Consumer to write $channel_id\n"; + $NS->Kill (); + $CON->Kill (); + exit 1; +} + +# discard old reconnect information +unlink $supplier_ids; + +# send 10 Any's, picking up the channel# from channel.id +$SUP->Arguments("-channel $channel_id -send 10 $client_args"); +if ($verbose eq "-v") {print "TEST SCRIPT: " . $SUP->CommandLine . "\n";} +$SUP->SpawnWaitKill(60); + +# forget the channel id, depend on the reconnect information +unlink $channel_id; + +$SUP->Arguments("-send 10 -serial_number 10 $client_args"); +if ($verbose eq "-v") {print "TEST SCRIPT: " . $SUP->CommandLine . "\n";} +$SUP->SpawnWaitKill(60); + +$status = $CON->WaitKill (60); + +if ($status) { + print STDERR "ERROR: Consumer reported error\n"; + $NS->Kill(); + exit $status; + } + +print "TEST SCRIPT: ****Passed: Supplier reconnect test.\n"; + +################ +#end of test 1 +################ + +# Now start the consumer again. Depending on reconnect this time +# Let it write the channel.id file so we know when it's up. + +if ($verbose eq "-v") {print "TEST SCRIPT: " . $CON->CommandLine . "\n";} +$CON->Spawn(); +# wait for the channel number file +if (PerlACE::waitforfile_timed ($channel_id, 10) == -1) { + print STDERR "ERROR: Timed out waiting for Consumer to write $channel_id\n"; + $NS->Kill (); + $CON->Kill (); + exit 1; +} + +# forget the channel id, depend on the supplier reconnect information +unlink $channel_id; + +$SUP->Arguments("-send 20 -serial_number 0 $client_args"); +if ($verbose eq "-v") {print "TEST SCRIPT: " . $SUP->CommandLine . "\n";} +$status= $SUP->SpawnWaitKill(60); +if ($status) { + print STDERR "ERROR: Supplier reported error\n"; + $CON->Kill(); + $NS->Kill(); + exit $status; + } + +$status = $CON->WaitKill (60); +if ($status) { + print STDERR "ERROR: Consumer reported error\n"; + $NS->Kill(); + exit $status; + } + +print "TEST SCRIPT: ****Passed: Consumer reconnect test.\n"; + +################ +#end of test 2 +################ + +if ($verbose eq "-v") {print "TEST SCRIPT: Stop the Notification Service\n";} +$NS->Kill(); +unlink $notify_ior; + +if ($verbose eq "-v") {print "TEST SCRIPT: Restarting Notify Service on port $notify_port\n";} +if ($verbose eq "-v") {print "TEST SCRIPT: It should load topology from $save_xml\n";} + +# sleep to avoid socket-related problems +sleep (10 * $PerlACE::Process::WAIT_DELAY_FACTOR); +$NS->Arguments($ns_args); +if ($verbose eq "-v") {print "TEST SCRIPT: " . $NS->CommandLine . "\n";} +$NS->Spawn(); + +# the ior file is only used to wait for the service to start +if (PerlACE::waitforfile_timed ($notify_ior, 10) == -1) { + print STDERR "ERROR: Timed out waiting for $notify_ior\n"; + $NS->Kill (); + exit 1; +} + +# Now start the consumer again. It will use the reconnect info. +# Let it write the channel.id file so we know when it's up. +unlink $channel_id; + +if ($verbose eq "-v") {print "TEST SCRIPT: " . $CON->CommandLine . "\n";} +$CON->Spawn(); +# wait for the channel number file +if (PerlACE::waitforfile_timed ($channel_id, 10) == -1) { + print STDERR "ERROR: Timed out waiting for Consumer to write $channel_id\n"; + $NS->Kill (); + $CON->Kill (); + exit 1; +} + +# forget the channel id, depend on the supplier reconnect information +unlink $channel_id; + +$SUP->Arguments("-send 20 -serial_number 0 $client_args"); +if ($verbose eq "-v") {print "TEST SCRIPT: " . $SUP->CommandLine . "\n";} +$status = $SUP->SpawnWaitKill(60); +if ($status) { + print STDERR "ERROR: Supplier reported error\n"; + $NS->Kill(); + $CON->Kill(); + exit $status; + } + +$status = $CON->WaitKill (60); +if ($status) { + print STDERR "ERROR: Consumer reported error\n"; + $NS->Kill(); + exit $status; + } + +print "TEST SCRIPT: ****Passed: Topology Persistence Test.\n"; + +################ +#end of test 3 +################ + +# Now start the consumer one more time +# Let it write the channel.id file so we know when it's up. +unlink $channel_id; + +if ($verbose eq "-v") {print "TEST SCRIPT: " . $CON->CommandLine . "\n";} +$CON->Spawn(); +# wait for the channel number file +if (PerlACE::waitforfile_timed ($channel_id, 10) == -1) { + print STDERR "ERROR: Timed out waiting for Consumer to write $channel_id\n"; + $NS->Kill (); + $CON->Kill (); + exit 1; +} + +# forget the channel id, depend on the supplier reconnect information +unlink $channel_id; + +# Start the Supplier, tell it to send 10 messages, pause until it is reconnected +# then send another 10. + +unlink ($supplier_pause); + +$SUP->Arguments("-send 20 -pause 10 -serial_number 0 $client_args"); +if ($verbose eq "-v") {print "TEST SCRIPT: " . $SUP->CommandLine . "\n";} +$SUP->Spawn(); + +# wait for the supplier's "paused" file +if (PerlACE::waitforfile_timed ($supplier_pause, 30) == -1) { + print STDERR "ERROR: Timed out waiting for Supplier to write $supplier_pause\n"; + $NS->Kill (); + $SUP->Kill (); + $CON->Kill (); + exit 1; +} +unlink ($supplier_pause); + +if ($verbose eq "-v") {print "TEST SCRIPT: Stop the Notification Service\n";} +$NS->Kill(); +unlink $notify_ior; + +if ($verbose eq "-v") {print "TEST SCRIPT: Restarting Notify Service\n";} +if ($verbose eq "-v") {print "TEST SCRIPT: Use unspecified port to make it \"invisible\" to clients\n";} +if ($verbose eq "-v") {print "TEST SCRIPT: It should load topology from $save_xml\n";} +if ($verbose eq "-v") {print "TEST SCRIPT: and reconnect to registered clients.\n";} + +#$NS->Arguments($ns_args_hidden); +# sleep to avoid socket-related problems +sleep (10 * $PerlACE::Process::WAIT_DELAY_FACTOR); + +if ($verbose eq "-v") {print "TEST SCRIPT: " . $NS->CommandLine . "\n";} +$NS->Spawn(); + +# at this point, both the consumer and the supplier should reconnect +# and the remaining events should be delivered +# eventually the consumer will finish + +$status = $CON->WaitKill (20); +if ($status) { + print STDERR "ERROR: Consumer reported error\n"; + $SUP->Kill(); + $NS->Kill(); + exit $status; + } + +$status = $SUP->Kill (); +if ($status) { + print STDERR "ERROR: Supplier reported error\n"; + $NS->Kill(); + exit $status; + } + +print "TEST SCRIPT: ****Passed: Reconnection Factory test.\n"; + +################ +#end of test 4 +################ + +if ($verbose eq "-v") {print "TEST SCRIPT: Stop the Notification Service\n";} +$NS->Kill(); + +unlink $notify_ior; +unlink $save_xml; +unlink $save_000; +unlink $eventpersist; +unlink $consumer_ids; +unlink $channel_id; +unlink $supplier_ids; + +sleep (10 * $PerlACE::Process::WAIT_DELAY_FACTOR); ## avoid lingering sockets +# go back to normal ns args +$NS->Arguments($ns_args); +if ($verbose eq "-v") {print "TEST SCRIPT: " . $NS->CommandLine . "\n";} +$NS->Spawn(); + +# the ior file is only used to wait for the service to start +if (PerlACE::waitforfile_timed ($notify_ior, 20) == -1) { + print STDERR "ERROR: Timed out waiting for $notify_ior\n"; + $NS->Kill (); + exit 1; +} + +#configure the consumer to expect 20 events, fail (throw an exception +# after 8 events) then continue to listen for remaining events. +#The Notification service should automatically retry (but may discard) +# the failed events. +$CON->Arguments("-channel $channel_id -expect 20 -fail 8 $client_args"); +if ($verbose eq "-v") {print "TEST SCRIPT: " . $CON->CommandLine . "\n";} +$CON->Spawn(); + +# wait for the channel number file +if (PerlACE::waitforfile_timed ($channel_id, 10) == -1) { + print STDERR "ERROR: Timed out waiting for Consumer to write $channel_id\n"; + $NS->Kill (); + $CON->Kill (); + exit 1; +} + +$SUP->Arguments("-channel $channel_id -send 20 $client_args"); +if ($verbose eq "-v") {print "TEST SCRIPT: " . $SUP->CommandLine . "\n";} +$status = $SUP->SpawnWaitKill(20); +if ($status) { + print STDERR "ERROR: Supplier reported error\n"; + $NS->Kill(); + $CON->Kill (); + exit $status; + } + +## this is a slow test due to the reconnection +## time, so give it enough time... +$status = $CON->WaitKill (240); + +if ($status) { + print STDERR "ERROR: Consumer reported error\n"; + $NS->Kill(); + exit $status; + } + +print "TEST SCRIPT: ****Passed: Consumer recoverable exception test.\n"; + +################ +#end of test 5 +################ + +if ($verbose eq "-v") {print "TEST SCRIPT: Stop the Notification Service\n";} +$NS->Kill(); +unlink $notify_ior; +unlink $save_xml; +unlink $save_000; +unlink $eventpersist; + +exit $status; diff --git a/TAO/orbsvcs/tests/Notify/XML_Persistence/XML_Persistence.mpc b/TAO/orbsvcs/tests/Notify/XML_Persistence/XML_Persistence.mpc new file mode 100644 index 00000000000..040b6dab9f0 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/XML_Persistence/XML_Persistence.mpc @@ -0,0 +1,2 @@ +project : orbsvcsexe, portableserver, notify_serv { +} diff --git a/TAO/orbsvcs/tests/Notify/XML_Persistence/main.cpp b/TAO/orbsvcs/tests/Notify/XML_Persistence/main.cpp new file mode 100644 index 00000000000..d5fc70bfc38 --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/XML_Persistence/main.cpp @@ -0,0 +1,360 @@ +/** + * $Id$ + */ + +#include <orbsvcs/orbsvcs/CosNotificationC.h> +#include <orbsvcs/orbsvcs/NotifyExtC.h> +#include <orbsvcs/orbsvcs/Notify/Notify_EventChannelFactory_i.h> + +#include <tao/TimeBaseC.h> +#include <tao/corba.h> +#include <tao/PortableServer/PortableServer.h> + +#include "ace/OS_NS_string.h" +#include <ace/OS_NS_stdio.h> +#include <ace/Dynamic_Service.h> +#include <ace/ARGV.h> + +class TestSupplier +: public POA_CosNotifyComm::StructuredPushSupplier +{ + virtual void disconnect_structured_push_supplier(ACE_ENV_SINGLE_ARG_DECL_NOT_USED) throw (CORBA::SystemException) { + } + + virtual void subscription_change( const CosNotification::EventTypeSeq&, + const CosNotification::EventTypeSeq& ACE_ENV_ARG_DECL_NOT_USED) + throw (CORBA::SystemException, CosNotifyComm::InvalidEventType) + { + } +}; + +class TestConsumer +: public POA_CosNotifyComm::StructuredPushConsumer +{ + virtual void disconnect_structured_push_consumer(ACE_ENV_SINGLE_ARG_DECL_NOT_USED) throw (CORBA::SystemException) { + } + + virtual void offer_change( const CosNotification::EventTypeSeq&, const CosNotification::EventTypeSeq& ACE_ENV_ARG_DECL_NOT_USED) + throw (CORBA::SystemException, CosNotifyComm::InvalidEventType) + { + } + + virtual void push_structured_event(const CosNotification::StructuredEvent& ACE_ENV_ARG_DECL_NOT_USED) + throw (CORBA::SystemException, CosEventComm::Disconnected) + { + } +}; + +int main(int ac, char **av) +{ + int retval = 1; + + bool pass1 = false; + bool pass2 = false; + ACE_DECLARE_NEW_CORBA_ENV; + ACE_TRY + { + CORBA::ORB_var orb; + PortableServer::POA_var poa; + + orb = CORBA::ORB_init(ac, av, "" ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + ACE_ASSERT(! CORBA::is_nil (orb.in ())); + + if (ac > 2 + && ACE_OS::strcmp (av[1], "-pass")) + { + int pn = av[2][0] - '0'; + switch (pn) + { + case 1: + pass1 = true; + pass2 = false; + break; + case 2: + pass1 = false; + pass2 = true; + break; + case 3: + pass1 = true; + pass2 = true; + break; + default: + fprintf (stderr, "Illegal -pass command line option. Expecting 1, 2, or 3\n"); + return -1; + } + } + if (! pass1 && !pass2) + { + FILE *f; + f = fopen ("loadtest.xml", "r"); + if (f != 0) + { + fclose (f); + pass1 = false; + pass2 = true; + } + else + { + pass1 = true; + pass2 = false; + } + } + CORBA::Object_var obj = + orb->resolve_initial_references("RootPOA" ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + ACE_ASSERT(! CORBA::is_nil (obj.in ())); + poa = PortableServer::POA::_narrow(obj.in () ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + ACE_ASSERT(! CORBA::is_nil (poa.in ())); + PortableServer::POAManager_var mgr = poa->the_POAManager(); + mgr->activate(); + + if (pass1) + { + CosNotifyChannelAdmin::EventChannelFactory_var cosecf = + TAO_Notify_EventChannelFactory_i::create(poa.in () ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + NotifyExt::EventChannelFactory_var ecf = + NotifyExt::EventChannelFactory::_narrow (cosecf.in () ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + if (CORBA::is_nil (ecf.in ())) + { + return -1; + } + + CosNotification::QoSProperties qosprops(7); + CORBA::ULong i = 0; + + qosprops.length(7); + qosprops[i].name = CORBA::string_dup(CosNotification::EventReliability); + qosprops[i++].value <<= CosNotification::Persistent; + qosprops[i].name = CORBA::string_dup(CosNotification::ConnectionReliability); + qosprops[i++].value <<= CosNotification::Persistent; // Required, or we won't persist much + qosprops[i].name = CORBA::string_dup(CosNotification::Priority); + qosprops[i++].value <<= CosNotification::HighestPriority; + qosprops[i].name = CORBA::string_dup(CosNotification::Timeout); + qosprops[i++].value <<= (TimeBase::TimeT) 42000; + qosprops[i].name = CORBA::string_dup(CosNotification::StopTimeSupported); + qosprops[i++].value <<= CORBA::Any::from_boolean(1); + qosprops[i].name = CORBA::string_dup(CosNotification::MaximumBatchSize); + qosprops[i++].value <<= (CORBA::Long) 555; + qosprops[i].name = CORBA::string_dup(CosNotification::PacingInterval); + qosprops[i++].value <<= (TimeBase::TimeT) 34300; + qosprops.length(i); + + CosNotification::AdminProperties adminprops(4); + adminprops.length(4); + i = 0; + adminprops[i].name = CORBA::string_dup(CosNotification::MaxQueueLength); + adminprops[i++].value <<= (CORBA::Long) 1234; + adminprops[i].name = CORBA::string_dup(CosNotification::MaxConsumers); + adminprops[i++].value <<= (CORBA::Long) 3; + adminprops[i].name = CORBA::string_dup(CosNotification::MaxSuppliers); + adminprops[i++].value <<= (CORBA::Long) 3; + adminprops[i].name = CORBA::string_dup(CosNotification::RejectNewEvents); + adminprops[i++].value <<= CORBA::Any::from_boolean(1); + adminprops.length (i); + + CosNotifyChannelAdmin::ChannelID ecid; + ::CosNotifyChannelAdmin::EventChannel_var ec = + ecf->create_channel(qosprops, adminprops, ecid ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + CosNotifyChannelAdmin::AdminID consumer_admin_id; + CosNotifyChannelAdmin::ConsumerAdmin_var ca = + ec->new_for_consumers(CosNotifyChannelAdmin::OR_OP, + consumer_admin_id + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + CosNotifyChannelAdmin::AdminID supplier_admin_id; + CosNotifyChannelAdmin::SupplierAdmin_var sa = + ec->new_for_suppliers(CosNotifyChannelAdmin::OR_OP, + supplier_admin_id + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + CosNotifyChannelAdmin::ProxyID proxy_id; + CosNotifyChannelAdmin::ProxySupplier_var ps = + ca->obtain_notification_push_supplier( + CosNotifyChannelAdmin::STRUCTURED_EVENT, + proxy_id + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + CosNotifyChannelAdmin::StructuredProxyPushSupplier_var strps = + CosNotifyChannelAdmin::StructuredProxyPushSupplier::_narrow(ps.in()); + + ps = ca->obtain_notification_push_supplier( + CosNotifyChannelAdmin::SEQUENCE_EVENT, + proxy_id + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + CosNotifyChannelAdmin::SequenceProxyPushSupplier_var seqps = + CosNotifyChannelAdmin::SequenceProxyPushSupplier::_narrow(ps.in()); + + ps = ca->obtain_notification_push_supplier( + CosNotifyChannelAdmin::ANY_EVENT, + proxy_id + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + CosNotifyChannelAdmin::ProxyPushSupplier_var anyps = + CosNotifyChannelAdmin::ProxyPushSupplier::_narrow(ps.in()); + + CosNotifyChannelAdmin::ProxyConsumer_var pc = + sa->obtain_notification_push_consumer( + CosNotifyChannelAdmin::STRUCTURED_EVENT, + proxy_id + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + CosNotifyChannelAdmin::StructuredProxyPushConsumer_var strpc = CosNotifyChannelAdmin::StructuredProxyPushConsumer::_narrow(pc.in()); + + pc = sa->obtain_notification_push_consumer( + CosNotifyChannelAdmin::SEQUENCE_EVENT, + proxy_id + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + CosNotifyChannelAdmin::SequenceProxyPushConsumer_var seqpc = CosNotifyChannelAdmin::SequenceProxyPushConsumer::_narrow(pc.in()); + + pc = + sa->obtain_notification_push_consumer( + CosNotifyChannelAdmin::ANY_EVENT, + proxy_id + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + CosNotifyChannelAdmin::ProxyPushConsumer_var anypc = CosNotifyChannelAdmin::ProxyPushConsumer::_narrow(pc.in()); + + CosNotifyFilter::FilterFactory_var ff = + ec->default_filter_factory (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + + CosNotifyFilter::Filter_var filter1 = + ff->create_filter("EXTENDED_TCL" ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + ACE_ASSERT(! CORBA::is_nil (filter1.in ())); + + CosNotifyFilter::Filter_var filter2 = + ff->create_filter("EXTENDED_TCL" ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + ACE_ASSERT(! CORBA::is_nil (filter2.in ())); + + CosNotifyFilter::ConstraintExpSeq constraint_list(1); + constraint_list.length(1); + constraint_list[0].event_types.length(0); + constraint_list[0].constraint_expr = CORBA::string_dup("Number == 100"); + + filter1->add_constraints(constraint_list ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + filter2->add_constraints(constraint_list ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + ca->add_filter (filter1.in() ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + sa->add_filter (filter2.in() ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + strps->add_filter (filter1.in() ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + seqps->add_filter (filter2.in() ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + anyps->add_filter (filter1.in() ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + strpc->add_filter (filter2.in() ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + seqpc->add_filter (filter1.in() ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + anypc->add_filter (filter1.in() ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + anypc->add_filter (filter2.in() ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + CosNotification::EventTypeSeq added1(1), removed1(0); + added1.length(1); + added1[0].domain_name = CORBA::string_dup("nightly_builds"); + added1[0].type_name = CORBA::string_dup("*"); + ca->subscription_change(added1, removed1 ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + // Connect a PushConsumer and PushSupplier + TestSupplier test_supplier_svt; + CosNotifyComm::StructuredPushSupplier_var push_sup = test_supplier_svt._this(); + TestConsumer test_consumer_svt; + CosNotifyComm::StructuredPushConsumer_var push_cons = test_consumer_svt._this(); + strpc->connect_structured_push_supplier(push_sup.in()); + strps->connect_structured_push_consumer(push_cons.in()); + + strps->suspend_connection(); + + ecf->destroy(ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + //////////////////////////////// + // TODO make this not hardcoded + ACE_OS::rename ("abc.xml", "loadtest.xml"); + + } // end of pass 1 + + if (pass2) + { + + // Create a new ecf, which should load itself from loadtest.xml + CosNotifyChannelAdmin::EventChannelFactory_var + cosecf = TAO_Notify_EventChannelFactory_i::create(poa.in () ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + ACE_TRY_CHECK; + NotifyExt::EventChannelFactory_var + ecf = NotifyExt::EventChannelFactory::_narrow (cosecf.in () ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + if (CORBA::is_nil (ecf.in ())) + { + return -1; + } + + // Force a change, which should write out a new abc.xml. + ecf->save_topology (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + + ecf->destroy(ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + } + + poa->destroy (1, 1 ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (1); + orb->destroy (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_CHECK_RETURN (1); + poa = PortableServer::POA::_nil (); + orb = CORBA::ORB::_nil (); + retval = 0; + } + ACE_CATCHANY + { + ACE_PRINT_EXCEPTION(ex, "Unexpected exception caught in main. "); + retval = -1; + } + ACE_CATCHALL + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("Error : Unknown exception caught in main.") )); + retval = -2; + } + ACE_ENDTRY; + return retval; +} diff --git a/TAO/orbsvcs/tests/Notify/XML_Persistence/run_test.pl b/TAO/orbsvcs/tests/Notify/XML_Persistence/run_test.pl new file mode 100755 index 00000000000..6b73d986e0f --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/XML_Persistence/run_test.pl @@ -0,0 +1,62 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +# ex + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::Run_Test; +use File::Compare; + +$ACE_ROOT = $ENV{ACE_ROOT}; +$TAO_ROOT = "$ACE_ROOT/TAO"; + +sub cleanup() { + unlink "loadtest.xml"; + unlink "abc.xml"; + for ($i = 0; $i < 10; ++$i) { + unlink "abc.00" . $i; + } + for ($i = 10; $i < 20; ++$i) { + unlink "abc.0" . $i; + } +} + +cleanup(); + +$ret = 0; + +$UTEST = new PerlACE::Process("main"); +$ret = $UTEST->SpawnWaitKill(10); +if ($ret != 0) { + print "ERROR : main returned $ret\n"; + exit $ret; +} + +# NOTE: In TAO 1.3a main ran the notification service twice +# producing both abc.xml and loadtest.xml. Unfortunately +# in TAO 1.4 the notification service will does not run +# successfully the second time in the same EXE. +# -- todo figure out why and fix it. +# Thus main was modified to run in two passes. If loadtest.xml +# exists, it runs pass 2. +$ret = $UTEST->SpawnWaitKill(10); +if ($ret != 0) { + print "ERROR : main returned $ret\n"; + exit $ret; +} + +$different = compare("loadtest.xml", "abc.xml"); +if ($different) { + print "ERROR : loadtest.xml != abc.xml\n"; + exit 1; +} else { + print "Success : loadtest.xml == abc.xml\n"; + cleanup(); +} + + +exit $ret; diff --git a/TAO/orbsvcs/tests/Notify/XML_Persistence/svc.conf b/TAO/orbsvcs/tests/Notify/XML_Persistence/svc.conf new file mode 100644 index 00000000000..10b21998a5b --- /dev/null +++ b/TAO/orbsvcs/tests/Notify/XML_Persistence/svc.conf @@ -0,0 +1,2 @@ +static Notify_Default_Event_Manager_Objects_Factory "-MTDispatching -DispatchingThreads 1" +dynamic Topology_Factory Service_Object* TAO_CosNotification_persist:_make_XML_Topology_Factory() "-save_base_path ./abc -load_base_path ./loadtest -backup_count 2 -no_timestamp" diff --git a/TAO/orbsvcs/tests/Notify/lib/Periodic_Consumer.cpp b/TAO/orbsvcs/tests/Notify/lib/Periodic_Consumer.cpp index 66d655dd9b6..efa4eb67f71 100644 --- a/TAO/orbsvcs/tests/Notify/lib/Periodic_Consumer.cpp +++ b/TAO/orbsvcs/tests/Notify/lib/Periodic_Consumer.cpp @@ -12,8 +12,8 @@ #include "LookupManager.h" #include "Priority_Mapping.h" -ACE_RCSID (RT_Notify, - TAO_Notify_Tests_Periodic_Consumer, +ACE_RCSID (RT_Notify, + TAO_Notify_Tests_Periodic_Consumer, "$Id$") int WARMUP_COUNT = 10; @@ -234,6 +234,8 @@ TAO_Notify_Tests_Periodic_Consumer::push_structured_event (const CosNotification // Eat CPU static CORBA::ULong prime_number = 9619; + (void)ACE::gcd (prime_number, prime_number/2 -1); + for (CORBA::ULong load = this->load_; load != 0; --load) ACE::is_prime (prime_number, 2, |