README.devmap 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146
  1. Copyright (c) 2002-2004 MontaVista Software, Inc.
  2. All rights reserved.
  3. This software licensed under BSD license, the text of which follows:
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are met:
  6. - Redistributions of source code must retain the above copyright notice,
  7. this list of conditions and the following disclaimer.
  8. - Redistributions in binary form must reproduce the above copyright notice,
  9. this list of conditions and the following disclaimer in the documentation
  10. and/or other materials provided with the distribution.
  11. - Neither the name of the MontaVista Software, Inc. nor the names of its
  12. contributors may be used to endorse or promote products derived from this
  13. software without specific prior written permission.
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  18. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  19. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  20. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  21. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  22. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  23. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  24. THE POSSIBILITY OF SUCH DAMAGE.
  25. -------------------------------------------------------------------------------
  26. This file provides a map for developers to understand how to contribute
  27. to the openais project. The purpose of this document is to prepare a
  28. developer to write a service for openais, or understand the architecture
  29. of openais.
  30. The following is described in this document:
  31. * all files, purpose, and dependencies
  32. * architecture of openais
  33. * taking advantage of virtual synchrony
  34. * adding libraries
  35. * adding services
  36. -------------------------------------------------------------------------------
  37. all files, purpose, and dependencies.
  38. -------------------------------------------------------------------------------
  39. *----------------*
  40. *- AIS INCLUDES -*
  41. *----------------*
  42. include/ais_amf.h
  43. -----------------
  44. Definitions for AMF interface.
  45. include/ais_ckpt.h
  46. ------------------
  47. Definitions for CKPT interface.
  48. include/ais_clm.h
  49. -----------------
  50. Definitions for CLM interface.
  51. include/ais_msg.h
  52. -----------------
  53. All the stuff that is used to specify how lib and executive communicate
  54. including message identifiers, message request data, and mesage response
  55. data.
  56. include/ais_types.h
  57. -------------------
  58. Base type definitions for AIS interface.
  59. include/list.h
  60. -------------
  61. Doubly linked list inline implementation.
  62. include/queue.h
  63. ---------------
  64. FIFO queue inline implementation.
  65. depends on list.
  66. include/sq.h
  67. ------------
  68. Sort queue where items are sorted according to a sequence number. Avoids
  69. Sort, hence, install of a new element takes is O(1). Inline implementation.
  70. depends on list.
  71. *---------------*
  72. * AIS LIBRARIES *
  73. *---------------*
  74. lib/amf.c
  75. ---------
  76. AMF user library linked into user application.
  77. lib/ckpt.c
  78. ----------
  79. CKPT user library linked into user application.
  80. lib/clm.c
  81. ---------
  82. CLM user library linked into user application.
  83. lib/util.c
  84. ----------
  85. Utility functions used by all libraries.
  86. *-----------------*
  87. *- AIS EXECUTIVE -*
  88. *-----------------*
  89. exec/amf.{h|c}
  90. -------------
  91. Server side implementation of Availability Management Framework (AMF API).
  92. exec/ckpt.{h|c}
  93. Server side implementation of Checkpointing (CKPT API).
  94. exec/clm.{h|c}
  95. Server side implementation of Cluster Membership (CLM API).
  96. exec/gmi.{h|c}
  97. --------------
  98. group messaging interface supporting reliable totally ordered group multicast
  99. using ring topology. Supports extended virtual synchrony delivery semantics
  100. with strong membership guarantees.
  101. depends on aispoll.
  102. depends on queue.
  103. depends on sq.
  104. depends on list.
  105. exec/handlers.h
  106. ---------------
  107. Functional specification of a service that connects into AIS executive.
  108. If all functions are implemented, new services can easily be added.
  109. exec/main.{h|c}
  110. --------------
  111. Main dispatch functionality and global data types used to connect AIS
  112. services into one component.
  113. exec/mempool.{h|c}
  114. ------------------
  115. Memory pool implementation that supports preallocated memory blocks to
  116. avoid OOM errors.
  117. exec/parse.{h|c}
  118. ----------------
  119. Parsing functions for parsing /etc/ais/groups.conf and
  120. /etc/ais/network.conf into internally used data structures.
  121. exec/aispoll.{h|c}
  122. ------------------
  123. poll abstraction with support for nearly unlimited large poll handlers
  124. and timer handlers.
  125. depends on tlist.
  126. exec/print.{h|c}
  127. ----------------
  128. Logging implementation meant to replace syslog. syslog has nasty side
  129. effect of causing a signal every time a message is logged.
  130. exec/tlist.{h|c}
  131. -----------------
  132. Timer list interface for supporting timer addition, removal, expiry, and
  133. determination of timeout period left for next timer to expire.
  134. depends on list.
  135. exec/log/print.{h|c}
  136. --------------------
  137. Prototype implementation of logging to syslog without using syslog C
  138. library call.
  139. loc
  140. ---
  141. Counts the lines of code in the AIS implementation.
  142. -------------------------------------------------------------------------------
  143. architecture of openais
  144. -------------------------------------------------------------------------------
  145. The openais project is a client server architecture. Libraries implement the
  146. SA Forum APIs and are linked into the end-application. Libraries request
  147. services from the ais executive. The ais executive uses the group messaging
  148. protocol to provide cluster communication between multiple processors (nodes).
  149. Once the group makes a decision, a response is sent to the library, which then
  150. responds to the user API.
  151. ----------------------------------------
  152. |AIS CLM, AMF, CKPT library (openais.a)|
  153. ----------------------------------------
  154. | Interprocess Communication |
  155. ----------------------------------------
  156. | openais Executive |
  157. | |
  158. | --------- --------- --------- |
  159. | | AMF | | CLM | | CKPT | |
  160. | |Service| |Service| |Service| |
  161. | --------- --------- --------- |
  162. | |
  163. | ----------- ----------- |
  164. | | Group | | Poll | |
  165. | |Messaging| |Interface| |
  166. | |Interface| ----------- |
  167. | ----------- |
  168. | |
  169. ----------------------------------------
  170. Figure 1: openais Architecture
  171. Every application that intends to use openais links with the libais library.
  172. This library uses IPC, or more specifically BSD unix sockets, to communicate
  173. with the executive. The library is a small program responsible only for
  174. packaging the request into a message. This message is sent, using IPC, to
  175. the executive which then processes it. The library then waits for a response.
  176. The library itself contains very little intelligence. Some utility services
  177. are provided:
  178. * create a connection to the executive
  179. * send messages to the executive
  180. * retrieve messages from the executive
  181. * Queue message for out of order delivery to library (used for async calls)
  182. * Poll on a fd
  183. * request the executive send a dummy message to break out of dispatch poll
  184. * create a handle instance
  185. * destroy a handle instance
  186. * get a reference to a handle instance
  187. * release a reference to a handle instance
  188. When a library connects, it sends via a message, the service type. The
  189. service type is stored and used later to reference the message handlers
  190. for both the library message handlers and executive message handlers.
  191. Every message sent contains an integer identifier, which is used to index
  192. into an array of message handlers to determine the correct message handler
  193. to execute.
  194. When a library sends a message via IPC, the delivery of the message occurs
  195. to the library message handler for the service specified in the service type.
  196. The library message handler is responsible for sending the message via the
  197. group messaging interface to all other processors (nodes) in the system via
  198. the API gmi_mcast(). In this way, the library handlers are also very simple
  199. containing no more logic then what is required to repackage the message into
  200. an executive message and send it via the group messaging interface.
  201. The group messaging interface sends the message according to the extended
  202. virtual synchrony model. The group messaging interface also delivers the
  203. message according to the extended virtual synchrony model. This has several
  204. advantages which are described in the virtual synchrony section. One
  205. advantage that must be described now is that messages are self-delivered;
  206. if a node sends a message, that same message is delivered back to that
  207. node.
  208. When the executive message is delivered, it is processed by the executive
  209. message handler. The executive message handler contains the brains of
  210. AIS and is responsible for making all decisions relating to the request
  211. from the libais library user.
  212. -------------------------------------------------------------------------------
  213. taking advantage of virtual synchrony
  214. -------------------------------------------------------------------------------
  215. definitions:
  216. processor: a system responsible for executing the virtual synchrony model
  217. configuration: the list of processors under which messages are delivered
  218. partition: one or more processors leave the configuration
  219. merge: one or more processors join the configuration
  220. group messaging: sending a message from one sender to many receivers
  221. Virtual synchrony is a model for group messaging. This is often confused
  222. with particular implementations of virtual synchrony. Try to focus on
  223. what virtual syncrhony provides, not how it provides it, unless interested
  224. in working on the group messaging interface of openais.
  225. Virtual synchrony provides several advantages:
  226. * integrated membership
  227. * strong membership guarantees
  228. * agreed ordering of delivered messages
  229. * same delivery of configuration changes and messages on every node
  230. * self-delivery
  231. * reliable communication in the face of unreliable networks
  232. * recovery of messages sent within a configuration where possible
  233. * use of network multicast using standard UDP/IP
  234. Integrated membership allows the group messaging interface to give
  235. configuration change events to the API services. This is obviously beneficial
  236. to the cluster membership service (and its respective API0, but is helpful
  237. to other services as described later.
  238. Strong membership guarantees allow a distributed application to make decisions
  239. based upon the configuration (membership). Every service in openais registers
  240. a configuration change function. This function is called whenever a
  241. configuration change occurs. The information passed is the current processors,
  242. the processors that have left the configuration, and the processors that have
  243. joined the configuration. This information is then used to make decisions
  244. within a distributed state machine. One example usage is that an AMF component
  245. running a specific processor has left the configuration, so failover actions
  246. must now be taken with the new configuration (and known components).
  247. Virtual synchrony requires that messages may be delivered in agreed order.
  248. FIFO order indicates that one sender and one receiver agree on the order of
  249. messages sent. Agreed ordering takes this requirement to groups, requiring that
  250. one sender and all receivers agree on the order of messages sent.
  251. Consider a lock service. The service is responsible for arbitrating locks
  252. between multiple processors in the system. With fifo ordering, this is very
  253. difficult because a request at about the same time for a lock from two seperate
  254. processors may arrive at all the receivers in different order. Agreed ordering
  255. ensures that all the processors are delivered the message in the same order.
  256. In this case the first lock message will always be from processor X, while the
  257. second lock message will always be from processor Y. Hence the first request
  258. is always honored by all processors, and the second request is rejected (since
  259. the lock is taken). This is how race conditions are avoided in distributed
  260. systems.
  261. Every processor is delivered a configuration change and messages within a
  262. configuration in the same order. This ensures that any distributed state
  263. machine will make the same decisions on every processor within the
  264. configuration. This also allows the configuration and the messages to be
  265. considered when making decisions.
  266. Virtual synchrony requires that every node is delivered messages that it
  267. sends. This enables the logic to be placed in one location (the handler
  268. for the delivery of the group message) instead of two seperate places. This
  269. also allows messages that are sent to be ordered in the stream of other
  270. messages within the configuration.
  271. Certain guarantees are required of virtually synchronous systems. If
  272. a message is sent, it must be delivered by every processor unless that
  273. processor fails. If a particular processor fails, a configuration change
  274. occurs creating a new configuration under which a new set of decisions
  275. may be made. This implies that even unreliable networks must reliably
  276. deliver messages. The implementation in openais works on unreliable as
  277. well as reliable networks.
  278. Every message sent must be delivered, unless a configuration change occurs.
  279. In the case of a configuration change, every message that can be recovered
  280. must be recovered before the new configuration is installed. Some systems
  281. during partition won't continue to recover messages within the old
  282. configuration even though those messages can be recovered. Virtual synchrony
  283. makes that impossible, except for those members that are no longer part
  284. of a configuration.
  285. Finally virtual syncrhony takes advantage of hardware multicast to avoid
  286. duplicated packets and scale to large transmit rates. On 100mbit network,
  287. openais can approach wire speeds depending on the number of messages queued
  288. for a particular processor.
  289. What does all of this mean for the developer?
  290. * messages are delivered reliably
  291. * messages are delivered in the same order to all nodes
  292. * configuration and messages can both be used to make decisions
  293. -------------------------------------------------------------------------------
  294. adding libraries
  295. -------------------------------------------------------------------------------
  296. The first stage in adding a library to the system is to develop the library.
  297. Library code should follow these guidelines:
  298. * use SA Forum coding style for APIs to aid in debugging
  299. * implement all library code within one file named after the api.
  300. examples are ckpt.c, clm.c, amf.c.
  301. * use parallel structure as much as possible between different APIs
  302. * make use of utility services provided by the library
  303. * if something is needed that is generic and useful by all services,
  304. submit patches for other libraries to use these services.
  305. * use the reference counting handle manager for handle management.
  306. ------------------
  307. Version checking
  308. ------------------
  309. struct saVersionDatabase {
  310. int versionCount;
  311. SaVersionT *versionsSupported;
  312. };
  313. The versionCount number describes how many entries are in the version database.
  314. The versionsSupported member is an array of SaVersionT describing the acceptable
  315. versions this API supports.
  316. An api developer specifies versions supported by adding the following C
  317. code to the library file:
  318. /*
  319. * Versions supported
  320. */
  321. static SaVersionT clmVersionsSupported[] = {
  322. { 'A', 1, 1 },
  323. { 'a', 1, 1 }
  324. };
  325. static struct saVersionDatabase clmVersionDatabase = {
  326. sizeof (clmVersionsSupported) / sizeof (SaVersionT),
  327. clmVersionsSupported
  328. };
  329. After this is specified, the following API is used to check versions:
  330. SaErrorT
  331. saVersionVerify (
  332. struct saVersionDatabase *versionDatabase,
  333. const SaVersionT *version);
  334. An example usage of this is
  335. SaErrorT error;
  336. error = saVersioNVerify (&clmVersionDatabase, version);
  337. where version is a pointer to an SaVersionT passed into the API.
  338. error will return SA_OK if the version is valid as specified in the
  339. version database.
  340. ------------------
  341. Handle Instances
  342. ------------------
  343. Every handle instance is stored in a handle database. The handle database
  344. stores instance information for every handle used by libraries. The system
  345. includes reference counting and is safe for use in threaded applications.
  346. The handle database structure is:
  347. struct saHandleDatabase {
  348. unsigned int handleCount;
  349. struct saHandle *handles;
  350. pthread_mutex_t mutex;
  351. void (*handleInstanceDestructor) (void *);
  352. };
  353. handleCount is the number of handles
  354. handles is an array of handles
  355. mutex is a pthread mutex used to mutually exclude access to the handle db
  356. handleInstanceDestructor is a callback that is called when the handle
  357. should be freed because its reference count as dropped to zero.
  358. The handle database is defined in a library as follows:
  359. static void clmHandleInstanceDestructor (void *);
  360. static struct saHandleDatabase clmHandleDatabase = {
  361. .handleCount = 0,
  362. .handles = 0,
  363. .mutex = PTHREAD_MUTEX_INITIALIZER,
  364. .handleInstanceDestructor = clmHandleInstanceDestructor
  365. };
  366. There are several APIs to access the handle database:
  367. SaErrorT
  368. saHandleCreate (
  369. struct saHandleDatabase *handleDatabase,
  370. int instanceSize,
  371. int *handleOut);
  372. Creates an instance of size instanceSize in the handleDatabase paraemter
  373. returning the handle number in handleOut. The handle instance reference
  374. count starts at the value 1.
  375. SaErrorT
  376. saHandleDestroy (
  377. struct saHandleDatabase *handleDatabase,
  378. unsigned int handle);
  379. Destroys further access to the handle. Once the handle reference count
  380. drops to zero, the database destructor is called for the handle. The handle
  381. instance reference count is decremented by 1.
  382. SaErrorT
  383. saHandleInstanceGet (
  384. struct saHandleDatabase *handleDatabase,
  385. unsigned int handle,
  386. void **instance);
  387. Gets an instance specified handle from the handleDatabase and returns
  388. it in the instance member. If the handle is valid SA_OK is returned
  389. otherwise an error is returned. This is used to ensure a handle is
  390. valid. Eveyr get call increases the reference count on a handle instance
  391. by one.
  392. SaErrorT
  393. saHandleInstancePut (
  394. struct saHandleDatabase *handleDatabase,
  395. unsigned int handle);
  396. Decrements the reference count by 1. If the reference count indicates
  397. the handle has been destroyed, it will then be removed from the database
  398. and the destructor called on the instance data. The put call takes care
  399. of freeing the handle instance data.
  400. Create a data structure for the instance, and use it within the libraries
  401. to store state information about the instance. This information can be
  402. the handle, a mutex for protecting I/O, a queue for queueing async messages
  403. or whatever is needed by the API.
  404. -----------------------------------
  405. communicating with the executive
  406. -----------------------------------
  407. A service connection is created with the following API;
  408. SaErrorT
  409. saServiceConnect (
  410. int *fdOut,
  411. enum req_init_types init_type);
  412. The fdOut parameter specifies the address where the file descriptor should
  413. be stored. This file descriptor should be stored within an instance structure
  414. returned by saHandleCreate.
  415. The init_type parameter specifies the service number to use when connecting.
  416. A message is sent to the executive with the function:
  417. SaErrorT
  418. saSendRetry (
  419. int s,
  420. const void *msg,
  421. size_t len,
  422. int flags);
  423. the s member is the socket to use retrieved with saServiceConnect
  424. the msg member is a pointer to the message to send to the service
  425. the len member is the length of the message to send
  426. the flags parameter is the flags to use with the sendmsg system call
  427. A message is received from the executive with the function:
  428. SaErrorT
  429. saRecvRetry (
  430. int s,
  431. void *msg,
  432. size_t len,
  433. int flags);
  434. the s member is the socket to use retrieved with saServiceConnect
  435. the msg member is a pointer to the message to receive to the service
  436. the len member is the length of the message to receive
  437. the flags parameter is the flags to use with the sendmsg system call
  438. A message is sent using io vectors with the following function:
  439. SaErrorT saSendMsgRetry (
  440. int s,
  441. struct iovec *iov,
  442. int iov_len);
  443. the s member is the socket to use retrieved with saServiceConnect
  444. the iov is an array of io vectors to send
  445. iov_len is the number of iovectors in iov
  446. Waiting for a file descriptor using poll systemcall is done with the api:
  447. SaErrorT
  448. saPollRetry (
  449. struct pollfd *ufds,
  450. unsigned int nfds,
  451. int timeout);
  452. where the parameters are the standard poll parameters.
  453. Messages can be received out of order searching for a specific message id with:
  454. SaErrorT
  455. saRecvQueue (
  456. int s,
  457. void *msg,
  458. struct queue *queue,
  459. int findMessageId);
  460. Where s is the socket to receive from
  461. where msg is the message address to receive to
  462. where queue is the queue to store messages if the message doens't match
  463. findMessageId is used to determine if a message matches (if its equal,
  464. it is received, if it isn't equal, it is stored in the queue)
  465. An API can activate the executive to send a dummy message with:
  466. SaErrorT
  467. saActivatePoll (int s);
  468. This is useful in dispatch functions to cause poll to drop out of waiting
  469. on a file descriptor when a connection is finalized.
  470. Looking at the lib/clm.c file is invaluable for showing how these APIs
  471. are used to communicate with the executive.
  472. ----------
  473. messages
  474. ----------
  475. Please follow the style of the messages. It makes debugging much easier
  476. if parallel style is used.
  477. An init message should be added to req_init_types.
  478. enum req_init_types {
  479. MESSAGE_REQ_CLM_INIT,
  480. MESSAGE_REQ_AMF_INIT,
  481. MESSAGE_REQ_CKPT_INIT,
  482. MESSAGE_REQ_CKPT_CHECKPOINT_INIT,
  483. MESSAGE_REQ_CKPT_SECTIONITERATOR_INIT
  484. };
  485. These are the request CLM message identifiers:
  486. Every library request message is defined in ais_msg.h and should look like this:
  487. enum req_clm_types {
  488. MESSAGE_REQ_CLM_TRACKSTART = 1,
  489. MESSAGE_REQ_CLM_TRACKSTOP,
  490. MESSAGE_REQ_CLM_NODEGET
  491. };
  492. These are the response CLM message identifiers:
  493. enum res_clm_types {
  494. MESSAGE_RES_CLM_TRACKCALLBACK = 1,
  495. MESSAGE_RES_CLM_NODEGET,
  496. MESSAGE_RES_CLM_NODEGETCALLBACK
  497. };
  498. index 0 of the message is special and is used for the activate poll message in
  499. every API. That is why req_clm_types and res_clm_types starts at 1.
  500. This is the message header that should start every message:
  501. struct message_header {
  502. int magic;
  503. int size;
  504. int id;
  505. };
  506. This is described later:
  507. struct message_source {
  508. struct conn_info *conn_info;
  509. struct in_addr in_addr;
  510. };
  511. This is the MESSAGE_REQ_CLM_TRACKSTART message id above:
  512. struct req_clm_trackstart {
  513. struct message_header header;
  514. SaUint8T trackFlags;
  515. SaClmClusterNotificationT *notificationBufferAddress;
  516. SaUint32T numberOfItems;
  517. };
  518. The saClmClusterTrackStart api should create this message and send it to the
  519. executive.
  520. responses should be of:
  521. struct res_clm_trackstart
  522. ----------------------------------------------------------------------
  523. Using one file descriptor for async and sync requests at the same time
  524. ----------------------------------------------------------------------
  525. A library may include async events but must also be able to handle
  526. sync request/responses on the same fd. This is achieved via the
  527. saRecvQueue() api call.
  528. 1. First have a look at exec/amf.c::saAmfInitialize.
  529. This function creates a queue to store responses that are not to be
  530. handled by the syncronous function, but instead meant to be handled by
  531. the dispatch (async) function.
  532. /*
  533. * An inq is needed to store async messages while waiting for a
  534. * sync response
  535. */
  536. error = saQueueInit (&amfInstance->inq, 512, sizeof (void *));
  537. if (error != SA_OK) {
  538. goto error_put_destroy;
  539. }
  540. 2. Next have a look at exec/amf.c::saAmfProtectionGroupTrackStart.
  541. This function must ensure that it gets a particular response, even when
  542. it may receive a request for a dispatch (async call). To solve this,
  543. the function queues the message on amfInstance->inq. It will only
  544. return a message in &req_amf_protectiongrouptrackstart once a message
  545. with MESSAGE_RES_AMF_PROTECTIONGROUPTRACKSTART defined in header->id of
  546. the response is received.
  547. error = saSendRetry (amfInstance->fd,
  548. &req_amf_protectiongrouptrackstart,
  549. sizeof (struct req_amf_protectiongrouptrackstart),
  550. MSG_NOSIGNAL);
  551. if (error != SA_OK) {
  552. goto error_unlock;
  553. }
  554. ^^^^^^ This code sends the request
  555. error = saRecvQueue (amfInstance->fd, &message,
  556. &amfInstance->inq, MESSAGE_RES_AMF_PROTECTIONGROUPTRACKSTART);
  557. ^^^^^^^^ This is the API which waits for a particular
  558. response. It will wait until a message with the header
  559. MESSAGE_RES_AMF_PROTECTIONGROUPTRACKSTART is received. Any other
  560. message it queues for the dispatch function to read the inq.
  561. 3. Finally have a look at the exec/amf/saAmfDispatch function.
  562. saQueueIsEmpty(&amfInstance->inq, &empty);
  563. if (empty == 0) {
  564. /*
  565. * Queue is not empty, read data from queue
  566. */
  567. saQueueItemGet (&amfInstance->inq, (void *)&queue_msg);
  568. msg = *queue_msg;
  569. memcpy (&dispatch_data, msg, msg->size);
  570. saQueueItemRemove (&amfInstance->inq);
  571. } else {
  572. /*
  573. * Queue empty, read response from socket
  574. */
  575. error = saRecvRetry (amfInstance->fd, &dispatch_data.header,
  576. sizeof (struct message_header), MSG_WAITALL |
  577. MSG_NOSIGNAL);
  578. if (error != SA_OK) {
  579. goto error_unlock;
  580. }
  581. if (dispatch_data.header.size > sizeof (struct
  582. message_header)) {
  583. error = saRecvRetry (amfInstance->fd,
  584. &dispatch_data.data,
  585. dispatch_data.header.size - sizeof (struct
  586. message_header),
  587. MSG_WAITALL | MSG_NOSIGNAL);
  588. if (error != SA_OK) {
  589. goto error_unlock;
  590. }
  591. }
  592. }
  593. This code basically checks if the queue is empty, then reads from the
  594. queue if there is a request, otherwise it reads from the socket.
  595. You might ask why doesn't the poll (not shown) block if there are
  596. messages in the queue but none in the socket. It doesn't block because
  597. every time a saRecvQueue queues a message, it sends a request to the
  598. executive (activate poll) which then sends a dummy message back to the
  599. library (activate poll) which keeps poll from blocking. The dummy
  600. message is ignored by the dispatch function.
  601. Not a great approach (the activate poll stuff). I have an idea to fix
  602. it though. Before a poll is ever done, the inq could be checked to see
  603. if it is empty. If there are messages on the inq, the dispatch function
  604. would not call poll, but instead indicate to the dispatch function to
  605. dispatch messages.
  606. Fortunately most of this activate poll mess is hidden from the library
  607. developer in saRecvQueue (this does the activate poll stuff). The
  608. develoepr simply has to be aware that the activate poll message is
  609. coming and ignore it appropriately.
  610. ------------
  611. some notes
  612. ------------
  613. * Avoid doing anything tricky in the library itself. Let the executive
  614. handler do all of the work of the system. minimize what the API does.
  615. * Once an api is developed, it must be added to the makefile. Just add
  616. a line for the file to EXECOBJS build line.
  617. * protect I/O send/recv with a mutex.
  618. * always look at other libraries when there is a question about how to
  619. do something. It has likely been thought out in another library.
  620. -------------------------------------------------------------------------------
  621. adding services
  622. -------------------------------------------------------------------------------
  623. Services are defined by service handlers and messages described in
  624. include/ais_msg.h. These two peices of information are used by the executive
  625. to dispatch the correct messages to the correct receipients.
  626. -------------------------------
  627. the service handler structure
  628. -------------------------------
  629. A service is added by defining a structure defined in exec/handlers.h. The
  630. structure is a little daunting:
  631. struct service_handler {
  632. int (**libais_handler_fns) (struct conn_info *conn_info, void *msg);
  633. int libais_handler_fns_count;
  634. int (**aisexec_handler_fns) (void *msg);
  635. int aisexec_handler_fns_count;
  636. int (*confchg_fn) (
  637. struct sockaddr_in *member_list, int member_list_entries,
  638. struct sockaddr_in *left_list, int left_list_entries,
  639. struct sockaddr_in *joined_list, int joined_list_entries);
  640. int (*libais_init_fn) (struct conn_info *conn_info, void *msg);
  641. int (*libais_exit_fn) (struct conn_info *conn_info);
  642. int (*aisexec_init_fn) (void);
  643. };
  644. libais_handler_fns are a list of functions that are dispatched by
  645. the executive when the library requests a service.
  646. libais_handler_fns_count is the number of functions in the handler list.
  647. aisexec_handler_fns are a list of functions that are dispatched by the
  648. group messaging interface when a message is delivered by the group messaging
  649. interface.
  650. aisexec_handler_fns_count is the number of functions in the aisexec_handler_fns
  651. list.
  652. confchg_fn is called every time a configuration change occurs.
  653. libais_init_fn is called every time a library connection is initialized.
  654. libais_exit_fn is called every time a library connection is terminated by
  655. the executive.
  656. aisexec_init_fn is called once during startup to initialize service specific
  657. data.
  658. ---------------------------
  659. look at a service handler
  660. ---------------------------
  661. A typical declaration of a full service is done in a file exec/service.c.
  662. Looking at exec/clm.c:
  663. static int (*clm_libais_handler_fns[]) (struct conn_info *conn_info, void *) = {
  664. message_handler_req_lib_activatepoll,
  665. message_handler_req_clm_trackstart,
  666. message_handler_req_clm_trackstop,
  667. message_handler_req_clm_nodeget
  668. };
  669. static int (*clm_aisexec_handler_fns[]) (void *) = {
  670. message_handler_req_exec_clm_nodejoin
  671. };
  672. struct service_handler clm_service_handler = {
  673. .libais_handler_fns = clm_libais_handler_fns,
  674. .libais_handler_fns_count = sizeof (clm_libais_handler_fns) / sizeof (int (*)),
  675. .aisexec_handler_fns = clm_aisexec_handler_fns ,
  676. .aisexec_handler_fns_count = sizeof (clm_aisexec_handler_fns) / sizeof (int (*)),
  677. .confchg_fn = clmConfChg,
  678. .libais_init_fn = message_handler_req_clm_init,
  679. .libais_exit_fn = clm_exit_fn,
  680. .aisexec_init_fn = clmExecutiveInitialize
  681. };
  682. if a library sends a message with id 0, message_handler_req_lib_activatepoll
  683. is called by the executive. If a message id of 1 is sent,
  684. message_handler_req_clm_trackstart is called.
  685. When a message is sent via the group messaging interface with the id of 0,
  686. message_handler_req_exec_clm_nodejoin is called.
  687. Whenever a new connection occurs from a library, message_handler_req_clm_init
  688. is called.
  689. Whenever a connection is terminated by the executive, clm_exit_fn is called.
  690. On startup, clmExecutiveInitialize is called.
  691. This service handler is exported via exec/clm.h as follows:
  692. extern struct service_handler clm_service_handler;
  693. ----------------------
  694. service handler list
  695. ----------------------
  696. Then the service handler is linked into the executive by adding an include
  697. for the clm.h to the main.c file and including the service in the service
  698. handlers array:
  699. /*
  700. * All service handlers in the AIS
  701. */
  702. struct service_handler *ais_service_handlers[] = {
  703. &clm_service_handler,
  704. &amf_service_handler,
  705. &ckpt_service_handler,
  706. &ckpt_checkpoint_service_handler,
  707. &ckpt_sectioniterator_service_handler
  708. };
  709. and including the definition (it is included already above).
  710. Make sure:
  711. #define AIS_SERVICE_HANDLERS_COUNT 5
  712. is defined to the number of entries in ais_service_handlers
  713. Within the main.h file is a list of the service types in the enum:
  714. enum socket_service_type {
  715. SOCKET_SERVICE_INIT,
  716. SOCKET_SERVICE_CLM,
  717. SOCKET_SERVICE_AMF,
  718. SOCKET_SERVICE_CKPT,
  719. SOCKET_SERVICE_CKPT_CHECKPOINT,
  720. SOCKET_SERVICE_CKPT_SECTIONITERATOR
  721. };
  722. SOCKET_SERVICE_CLM = service handler 0, SOCKET_SERVICE_AMF = service
  723. handler 1, etc.
  724. -------------------------
  725. the conn_info structure
  726. -------------------------
  727. information about a particular connection is stored in the connection
  728. information structure.
  729. struct conn_info {
  730. int fd; /* File descriptor for this connection */
  731. int active; /* Does this file descriptor have an active connection */
  732. char *inb; /* Input buffer for non-blocking reads */
  733. int inb_nextheader; /* Next message header starts here */
  734. int inb_start; /* Start location of input buffer */
  735. int inb_inuse; /* Bytes currently stored in input buffer */
  736. struct queue outq; /* Circular queue for outgoing requests */
  737. int byte_start; /* Byte to start sending from in head of queue */
  738. enum socket_service_type service;/* Type of service so dispatch knows how to route message */
  739. struct saAmfComponent *component; /* Component for which this connection relates to TODO shouldn't this be in the ci structure */
  740. int authenticated; /* Is this connection authenticated? */
  741. struct list_head conn_list;
  742. struct ais_ci ais_ci; /* libais connection information */
  743. };
  744. This structure is daunting, but don't worry it rarely needs to be manipulated.
  745. The only two members that should ever be accessed by a service are service
  746. (which is set during the library init call) and ais_ci which is used to store
  747. connection specific information.
  748. The connection specific information is:
  749. struct ais_ci {
  750. struct sockaddr_un un_addr; /* address of AF_UNIX socket, MUST BE FIRST IN STRUCTURE */
  751. union {
  752. struct aisexec_ci aisexec_ci;
  753. struct libclm_ci libclm_ci;
  754. struct libamf_ci libamf_ci;
  755. struct libckpt_ci libckpt_ci;
  756. } u;
  757. };
  758. If adding a service, a new structure should be defined in main.h and added
  759. to the union u in ais_ci. This union can then be used to access connection
  760. specific information and mantain state securely.
  761. ------------------------------
  762. sending responses to the api
  763. ------------------------------
  764. A message is sent to the library from the executive message handler using
  765. the function:
  766. extern int libais_send_response (struct conn_info *conn_info, void *msg,
  767. int mlen);
  768. conn_info is passed into the library message handler or stored in the
  769. executive message. This member describes the connection to send the response.
  770. msg is the message to send
  771. mlen is the length of the message to send
  772. --------------------------------------------
  773. deferring response to an executive message
  774. --------------------------------------------
  775. THe source structure is used to store information about the source of a
  776. message so a later executive message can respond to a library request. In
  777. a library handler, the source field should be set up with:
  778. msg.source.conn_info = conn_info;
  779. msg.source.s_addr = this_ip.sin_addr.s_addr;
  780. gmi_mcast (msg)
  781. In this case conn_info is passed into the library message handler
  782. Then the executive message handler determines if this processor is responsible
  783. for responding:
  784. if (req_exec_amf_componentregister->source.in_addr.s_addr ==
  785. this_ip.sin_addr.s_addr) {
  786. libais_send_response ();
  787. }
  788. Not pretty, but it works :)
  789. ----------------------------
  790. sending messages using gmi
  791. ----------------------------
  792. To send a message to every processor and the local processor for self
  793. delivery according to virtual synchrony semantics use:
  794. #define GMI_PRIO_HIGH 0
  795. #define GMI_PRIO_MED 1
  796. #define GMI_PRIO_LOW 2
  797. int gmi_mcast (
  798. struct gmi_groupname *groupname,
  799. struct iovec *iovec,
  800. int iov_len,
  801. int priority);
  802. groupname is a global and should always be aisexec_groupname
  803. An example usage of this function is:
  804. struct req_exec_clm_nodejoin req_exec_clm_nodejoin;
  805. struct iovec req_exec_clm_iovec;
  806. int result;
  807. req_exec_clm_nodejoin.header.magic = MESSAGE_MAGIC;
  808. req_exec_clm_nodejoin.header.size =
  809. sizeof (struct req_exec_clm_nodejoin);
  810. req_exec_clm_nodejoin.header.id = MESSAGE_REQ_EXEC_CLM_NODEJOIN;
  811. memcpy (&req_exec_clm_nodejoin.clusterNode, &thisClusterNode,
  812. sizeof (SaClmClusterNodeT));
  813. req_exec_clm_iovec.iov_base = &req_exec_clm_nodejoin;
  814. req_exec_clm_iovec.iov_len = sizeof (req_exec_clm_nodejoin);
  815. result = gmi_mcast (&aisexec_groupname, &req_exec_clm_iovec, 1,
  816. GMI_PRIO_HIGH);
  817. Notice the priority field. Priorities are used when determining which
  818. queued messages to send first. Higher priority messages (on one processor)
  819. are sent before lower priority messages.
  820. -----------------
  821. library handler
  822. -----------------
  823. Every library handler has the prototype:
  824. static int message_handler_req_clm_init (struct conn_info *conn_info,
  825. void *message);
  826. The start of the handler function should look something like this:
  827. int message_handler_req_clm_trackstart (struct conn_info *conn_info,
  828. void *message)
  829. {
  830. struct req_clm_trackstart *req_clm_trackstart =
  831. (struct req_clm_trackstart *)message;
  832. { package up library handler message into executive message }
  833. }
  834. This assigns the void *message to a structure that can be used by the
  835. library handler.
  836. The conn_info field is used to indicate where the response should respond to.
  837. Use the tricks described in deferring a response to the executive handler to
  838. have the executive handler respond to the message.
  839. avoid doing anything tricky in a library handler. Do all the work in the
  840. executive handler at first. If later, it is possible to optimize, optimize
  841. away.
  842. -------------------
  843. executive handler
  844. -------------------
  845. Every executive handler has the prototype:
  846. static int message_handler_req_exec_clm_nodejoin (void *message);
  847. The start of the handler function should look something like this:
  848. static int message_handler_req_exec_clm_nodejoin (void *message);
  849. {
  850. struct req_exec_clm_nodejoin *req_exec_clm_nodejoin = (struct req_exec_clm_nodejoin *)message;
  851. { do real work of executing request, this is done on every node }
  852. }
  853. The conn_info structure is not available. If it is needed, it can be stored
  854. in the message sent by the library message handler in a source structure.
  855. The message field contains the message sent by the library handler
  856. --------------------
  857. the libais_init_fn
  858. --------------------
  859. This function is responsible for authenticating the connection. If it is
  860. not properly implemented, no further communication to the executive on that
  861. connection will work. Copy the init function from some other service
  862. changing what looks obvious.
  863. --------------------
  864. the libais_exit_fn
  865. --------------------
  866. This function is called every time a service connection is disconnected by
  867. the executive. Free memory, change structures, or whatever work needs to
  868. be done to clean up.
  869. ----------------
  870. the confchg_fn
  871. ----------------
  872. This function is called whenever a configuration change occurs. Some
  873. services may not need this function, while others may. This is a good way
  874. to sync up joining nodes with the current state of the information stored
  875. on a particular processor.
  876. -------------------------------------------------------------------------------
  877. Final comments
  878. -------------------------------------------------------------------------------
  879. GDB is your friend, especially the "where" command. But it stops execution.
  880. This has a nasty side effect of killing the current configuration. In this
  881. case GDB may become your enemy.
  882. printf is your friend when GDB is your enemy.
  883. If stuck, ask on the mailing list, send your patches. Alot of time has been
  884. spent designing openais, and even more time debugging it. There are people
  885. that can help you debug problems, especially around things like message
  886. delivery.
  887. Submit patches early to get feedback, especially around things like parallel
  888. style. Parallel style is very important to ensure maintainability by the
  889. openais community.
  890. If this document is wrong or incomplete, complain so we can get it fixed
  891. for other people.
  892. Have fun!