1 /* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef GCS_CONTROL_INTERFACE_INCLUDED
24 #define GCS_CONTROL_INTERFACE_INCLUDED
25 
26 #include "gcs_control_event_listener.h"
27 #include "gcs_member_identifier.h"
28 #include "gcs_view.h"
29 
30 #include <vector>
31 
32 /**
33   @class Gcs_control_interface
34 
35   This interface represents all the control functionalities that a binding
36   implementation must provide. Like all interfaces in this API, it is
37   group-oriented, meaning that a single instance shall exist per group,
38   as it was returned by the class Gcs_interface::get_control_session.
39 
40   It contains methods for:
41   - View Membership;
42   - Control Events;
43   - Generic Data Exchange.
44 
45   View Membership contain operations that will conduct one to:
46   - Belong to a group: join() and leave();
47   - Information about its status: belongs_to_group() and
48     get_current_view() that shall return the active Gcs_view.
49 
50   Due to the asynchronous nature of this interface, the results of
51   join() and leave() operations, in local or remote members, shall come
52   via an event. Those events shall be delivered in form of callbacks
53   defined in Gcs_control_event_listener, that should be implemented by a
54   client of this interface interested in receiving those notifications.
55 
56   Regarding Generic Data Exchange, it is a functionality that was created
57   to allow exchange of arbitrary data among members when one joins.
58   This generic data is retrieved via the callback get_exchangeable_data() each
59   time a View Change (VC) occurs. It states the data that one would like to
60   offer in exchange whenever a VC happens.
61 
62   What must happen under the hood is that, when one receives a VC from
63   the underlying GCS, the binding implementation should start a round
64   of message exchange, in which members (one or all depending of the algorithm)
65   send the Exchangeable Data to the joining node.
66 
67   That data is delivered when Gcs_control_event_listener::on_view_changed is
68   called, which hands-out all exchanged data in one point in time.
69 
70   A typical usage for that interface would be:
71 
72   @code{.cpp}
73   class my_Gcs_control_event_listener: Gcs_control_event_listener
74   {
75     void on_view_changed(const Gcs_view *new_view,
76                          const Exchanged_data &exchanged_data)
77     {
78       // D something when view arrives...
79       // It will also deliver all data that nodes decided to offer at join()
80       // time
81     }
82 
83     Gcs_message_data &get_exchangeable_data()
84     {
85       // Return whatever data we want to provide to a joining node
86     }
87   }
88 
89   // Meanwhile in your client code...
90   Gcs_control_interface *gcs_control_interface_instance; // obtained
91                                                          // previously
92 
93   Gcs_control_event_listener *listener_instance=
94     new my_Gcs_control_event_listener();
95 
96   int ref_handler=
97     gcs_control_interface_instance->add_event_listener(listener_instance);
98 
99   // Normal program flow... join(), send_message(), leave()...
100 
101   gcs_control_interface_instance->join();
102 
103   gcs_control_interface_instance->leave();
104 
105   // In the end...
106   gcs_control_interface_instance->remove_event_listener(ref_handler);
107 
108   @endcode
109 */
110 class Gcs_control_interface
111 {
112 public:
113   /**
114     Method that causes one to join the group that this
115     interface pertains.
116 
117     The method is non-blocking, meaning that it shall only send the
118     request to an underlying GCS. The final result shall come via a
119     View Change event delivered through Gcs_control_event_listener.
120 
121     @retval GCS_OK in case of everything goes well. Any other value of
122             gcs_error in case of error.
123    */
124 
125   virtual enum_gcs_error join()= 0;
126 
127 
128   /**
129     Method that causes one to leave the group that this
130     interface pertains.
131 
132     The method is non-blocking, meaning that it shall only send the
133     request to an underlying GCS. The final result shall come via a
134     View Change event delivered through Gcs_control_event_listener.
135 
136     @retval GCS_OK in case of everything goes well. Any other value of
137             gcs_error in case of error
138    */
139 
140   virtual enum_gcs_error leave()= 0;
141 
142 
143   /**
144     Reports if one has joined and belongs to a group.
145 
146     @retval true if belonging to a group
147   */
148 
149   virtual bool belongs_to_group()= 0;
150 
151 
152   /**
153     Returns the currently installed view.
154 
155     @retval - a valid pointer to a Gcs_view object.
156               If one has left a group, this shall be the last
157               installed view. That view can be considered a best-effort
158               view since, in some GCSs, the one that leaves might not
159               have access to the exchanged information.
160     @retval - NULL if one never joined a group.
161   */
162 
163   virtual Gcs_view *get_current_view()= 0;
164 
165 
166   /**
167     Retrieves the local identifier of this member on a group.
168 
169     @retval - a reference to a valid Gcs_member_identifier instance
170     @retval - NULL in case of error
171   */
172 
173   virtual const Gcs_member_identifier get_local_member_identifier() const= 0;
174 
175 
176   /**
177     Registers an implementation of a Gcs_control_event_listener that will
178     receive Control Events. See the class header for more details on
179     implementations and usage.
180 
181     Note that a binding implementation shall not offer the possibility of
182     changing listeners while the system is up and running. In that sense,
183     listeners must be added to it only when booting up the system.
184 
185     @param[in] event_listener a class that implements Gcs_control_event_listener
186     @return an handle representing the registration of this object to
187             be used in remove_event_listener
188   */
189 
190   virtual int
191   add_event_listener(const Gcs_control_event_listener &event_listener)= 0;
192 
193 
194   /**
195     Removes a previously registered event listener.
196 
197     Note that a binding implementation shall not offer the possibility of
198     changing listeners while the system is up and running. In that sense
199     listeners must be removed from it only when shutting down the system.
200 
201     @param[in] event_listener_handle the handle returned when the listener was
202                                      registered
203    */
204 
205   virtual void remove_event_listener(int event_listener_handle)= 0;
206 
207 
~Gcs_control_interface()208   virtual ~Gcs_control_interface() {}
209 };
210 
211 #endif // GCS_CONTROL_INTERFACE_INCLUDED
212