README.devmap 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  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. some notes
  524. ------------
  525. * Avoid doing anything tricky in the library itself. Let the executive
  526. handler do all of the work of the system. minimize what the API does.
  527. * Once an api is developed, it must be added to the makefile. Just add
  528. a line for the file to EXECOBJS build line.
  529. * protect I/O send/recv with a mutex.
  530. * always look at other libraries when there is a question about how to
  531. do something. It has likely been thought out in another library.
  532. -------------------------------------------------------------------------------
  533. adding services
  534. -------------------------------------------------------------------------------
  535. Services are defined by service handlers and messages described in
  536. include/ais_msg.h. These two peices of information are used by the executive
  537. to dispatch the correct messages to the correct receipients.
  538. -------------------------------
  539. the service handler structure
  540. -------------------------------
  541. A service is added by defining a structure defined in exec/handlers.h. The
  542. structure is a little daunting:
  543. struct service_handler {
  544. int (**libais_handler_fns) (struct conn_info *conn_info, void *msg);
  545. int libais_handler_fns_count;
  546. int (**aisexec_handler_fns) (void *msg);
  547. int aisexec_handler_fns_count;
  548. int (*confchg_fn) (
  549. struct sockaddr_in *member_list, int member_list_entries,
  550. struct sockaddr_in *left_list, int left_list_entries,
  551. struct sockaddr_in *joined_list, int joined_list_entries);
  552. int (*libais_init_fn) (struct conn_info *conn_info, void *msg);
  553. int (*libais_exit_fn) (struct conn_info *conn_info);
  554. int (*aisexec_init_fn) (void);
  555. };
  556. libais_handler_fns are a list of functions that are dispatched by
  557. the executive when the library requests a service.
  558. libais_handler_fns_count is the number of functions in the handler list.
  559. aisexec_handler_fns are a list of functions that are dispatched by the
  560. group messaging interface when a message is delivered by the group messaging
  561. interface.
  562. aisexec_handler_fns_count is the number of functions in the aisexec_handler_fns
  563. list.
  564. confchg_fn is called every time a configuration change occurs.
  565. libais_init_fn is called every time a library connection is initialized.
  566. libais_exit_fn is called every time a library connection is terminated by
  567. the executive.
  568. aisexec_init_fn is called once during startup to initialize service specific
  569. data.
  570. ---------------------------
  571. look at a service handler
  572. ---------------------------
  573. A typical declaration of a full service is done in a file exec/service.c.
  574. Looking at exec/clm.c:
  575. static int (*clm_libais_handler_fns[]) (struct conn_info *conn_info, void *) = {
  576. message_handler_req_lib_activatepoll,
  577. message_handler_req_clm_trackstart,
  578. message_handler_req_clm_trackstop,
  579. message_handler_req_clm_nodeget
  580. };
  581. static int (*clm_aisexec_handler_fns[]) (void *) = {
  582. message_handler_req_exec_clm_nodejoin
  583. };
  584. struct service_handler clm_service_handler = {
  585. .libais_handler_fns = clm_libais_handler_fns,
  586. .libais_handler_fns_count = sizeof (clm_libais_handler_fns) / sizeof (int (*)),
  587. .aisexec_handler_fns = clm_aisexec_handler_fns ,
  588. .aisexec_handler_fns_count = sizeof (clm_aisexec_handler_fns) / sizeof (int (*)),
  589. .confchg_fn = clmConfChg,
  590. .libais_init_fn = message_handler_req_clm_init,
  591. .libais_exit_fn = clm_exit_fn,
  592. .aisexec_init_fn = clmExecutiveInitialize
  593. };
  594. if a library sends a message with id 0, message_handler_req_lib_activatepoll
  595. is called by the executive. If a message id of 1 is sent,
  596. message_handler_req_clm_trackstart is called.
  597. When a message is sent via the group messaging interface with the id of 0,
  598. message_handler_req_exec_clm_nodejoin is called.
  599. Whenever a new connection occurs from a library, message_handler_req_clm_init
  600. is called.
  601. Whenever a connection is terminated by the executive, clm_exit_fn is called.
  602. On startup, clmExecutiveInitialize is called.
  603. This service handler is exported via exec/clm.h as follows:
  604. extern struct service_handler clm_service_handler;
  605. ----------------------
  606. service handler list
  607. ----------------------
  608. Then the service handler is linked into the executive by adding an include
  609. for the clm.h to the main.c file and including the service in the service
  610. handlers array:
  611. /*
  612. * All service handlers in the AIS
  613. */
  614. struct service_handler *ais_service_handlers[] = {
  615. &clm_service_handler,
  616. &amf_service_handler,
  617. &ckpt_service_handler,
  618. &ckpt_checkpoint_service_handler,
  619. &ckpt_sectioniterator_service_handler
  620. };
  621. and including the definition (it is included already above).
  622. Make sure:
  623. #define AIS_SERVICE_HANDLERS_COUNT 5
  624. is defined to the number of entries in ais_service_handlers
  625. Within the main.h file is a list of the service types in the enum:
  626. enum socket_service_type {
  627. SOCKET_SERVICE_INIT,
  628. SOCKET_SERVICE_CLM,
  629. SOCKET_SERVICE_AMF,
  630. SOCKET_SERVICE_CKPT,
  631. SOCKET_SERVICE_CKPT_CHECKPOINT,
  632. SOCKET_SERVICE_CKPT_SECTIONITERATOR
  633. };
  634. SOCKET_SERVICE_CLM = service handler 0, SOCKET_SERVICE_AMF = service
  635. handler 1, etc.
  636. -------------------------
  637. the conn_info structure
  638. -------------------------
  639. information about a particular connection is stored in the connection
  640. information structure.
  641. struct conn_info {
  642. int fd; /* File descriptor for this connection */
  643. int active; /* Does this file descriptor have an active connection */
  644. char *inb; /* Input buffer for non-blocking reads */
  645. int inb_nextheader; /* Next message header starts here */
  646. int inb_start; /* Start location of input buffer */
  647. int inb_inuse; /* Bytes currently stored in input buffer */
  648. struct queue outq; /* Circular queue for outgoing requests */
  649. int byte_start; /* Byte to start sending from in head of queue */
  650. enum socket_service_type service;/* Type of service so dispatch knows how to route message */
  651. struct saAmfComponent *component; /* Component for which this connection relates to TODO shouldn't this be in the ci structure */
  652. int authenticated; /* Is this connection authenticated? */
  653. struct list_head conn_list;
  654. struct ais_ci ais_ci; /* libais connection information */
  655. };
  656. This structure is daunting, but don't worry it rarely needs to be manipulated.
  657. The only two members that should ever be accessed by a service are service
  658. (which is set during the library init call) and ais_ci which is used to store
  659. connection specific information.
  660. The connection specific information is:
  661. struct ais_ci {
  662. struct sockaddr_un un_addr; /* address of AF_UNIX socket, MUST BE FIRST IN STRUCTURE */
  663. union {
  664. struct aisexec_ci aisexec_ci;
  665. struct libclm_ci libclm_ci;
  666. struct libamf_ci libamf_ci;
  667. struct libckpt_ci libckpt_ci;
  668. } u;
  669. };
  670. If adding a service, a new structure should be defined in main.h and added
  671. to the union u in ais_ci. This union can then be used to access connection
  672. specific information and mantain state securely.
  673. ------------------------------
  674. sending responses to the api
  675. ------------------------------
  676. A message is sent to the library from the executive message handler using
  677. the function:
  678. extern int libais_send_response (struct conn_info *conn_info, void *msg,
  679. int mlen);
  680. conn_info is passed into the library message handler or stored in the
  681. executive message. This member describes the connection to send the response.
  682. msg is the message to send
  683. mlen is the length of the message to send
  684. --------------------------------------------
  685. deferring response to an executive message
  686. --------------------------------------------
  687. THe source structure is used to store information about the source of a
  688. message so a later executive message can respond to a library request. In
  689. a library handler, the source field should be set up with:
  690. msg.source.conn_info = conn_info;
  691. msg.source.s_addr = this_ip.sin_addr.s_addr;
  692. gmi_mcast (msg)
  693. In this case conn_info is passed into the library message handler
  694. Then the executive message handler determines if this processor is responsible
  695. for responding:
  696. if (req_exec_amf_componentregister->source.in_addr.s_addr ==
  697. this_ip.sin_addr.s_addr) {
  698. libais_send_response ();
  699. }
  700. Not pretty, but it works :)
  701. ----------------------------
  702. sending messages using gmi
  703. ----------------------------
  704. To send a message to every processor and the local processor for self
  705. delivery according to virtual synchrony semantics use:
  706. #define GMI_PRIO_HIGH 0
  707. #define GMI_PRIO_MED 1
  708. #define GMI_PRIO_LOW 2
  709. int gmi_mcast (
  710. struct gmi_groupname *groupname,
  711. struct iovec *iovec,
  712. int iov_len,
  713. int priority);
  714. groupname is a global and should always be aisexec_groupname
  715. An example usage of this function is:
  716. struct req_exec_clm_nodejoin req_exec_clm_nodejoin;
  717. struct iovec req_exec_clm_iovec;
  718. int result;
  719. req_exec_clm_nodejoin.header.magic = MESSAGE_MAGIC;
  720. req_exec_clm_nodejoin.header.size =
  721. sizeof (struct req_exec_clm_nodejoin);
  722. req_exec_clm_nodejoin.header.id = MESSAGE_REQ_EXEC_CLM_NODEJOIN;
  723. memcpy (&req_exec_clm_nodejoin.clusterNode, &thisClusterNode,
  724. sizeof (SaClmClusterNodeT));
  725. req_exec_clm_iovec.iov_base = &req_exec_clm_nodejoin;
  726. req_exec_clm_iovec.iov_len = sizeof (req_exec_clm_nodejoin);
  727. result = gmi_mcast (&aisexec_groupname, &req_exec_clm_iovec, 1,
  728. GMI_PRIO_HIGH);
  729. Notice the priority field. Priorities are used when determining which
  730. queued messages to send first. Higher priority messages (on one processor)
  731. are sent before lower priority messages.
  732. -----------------
  733. library handler
  734. -----------------
  735. Every library handler has the prototype:
  736. static int message_handler_req_clm_init (struct conn_info *conn_info,
  737. void *message);
  738. The start of the handler function should look something like this:
  739. int message_handler_req_clm_trackstart (struct conn_info *conn_info,
  740. void *message)
  741. {
  742. struct req_clm_trackstart *req_clm_trackstart =
  743. (struct req_clm_trackstart *)message;
  744. { package up library handler message into executive message }
  745. }
  746. This assigns the void *message to a structure that can be used by the
  747. library handler.
  748. The conn_info field is used to indicate where the response should respond to.
  749. Use the tricks described in deferring a response to the executive handler to
  750. have the executive handler respond to the message.
  751. avoid doing anything tricky in a library handler. Do all the work in the
  752. executive handler at first. If later, it is possible to optimize, optimize
  753. away.
  754. -------------------
  755. executive handler
  756. -------------------
  757. Every executive handler has the prototype:
  758. static int message_handler_req_exec_clm_nodejoin (void *message);
  759. The start of the handler function should look something like this:
  760. static int message_handler_req_exec_clm_nodejoin (void *message);
  761. {
  762. struct req_exec_clm_nodejoin *req_exec_clm_nodejoin = (struct req_exec_clm_nodejoin *)message;
  763. { do real work of executing request, this is done on every node }
  764. }
  765. The conn_info structure is not available. If it is needed, it can be stored
  766. in the message sent by the library message handler in a source structure.
  767. The message field contains the message sent by the library handler
  768. --------------------
  769. the libais_init_fn
  770. --------------------
  771. This function is responsible for authenticating the connection. If it is
  772. not properly implemented, no further communication to the executive on that
  773. connection will work. Copy the init function from some other service
  774. changing what looks obvious.
  775. --------------------
  776. the libais_exit_fn
  777. --------------------
  778. This function is called every time a service connection is disconnected by
  779. the executive. Free memory, change structures, or whatever work needs to
  780. be done to clean up.
  781. ----------------
  782. the confchg_fn
  783. ----------------
  784. This function is called whenever a configuration change occurs. Some
  785. services may not need this function, while others may. This is a good way
  786. to sync up joining nodes with the current state of the information stored
  787. on a particular processor.
  788. -------------------------------------------------------------------------------
  789. Final comments
  790. -------------------------------------------------------------------------------
  791. GDB is your friend, especially the "where" command. But it stops execution.
  792. This has a nasty side effect of killing the current configuration. In this
  793. case GDB may become your enemy.
  794. printf is your friend when GDB is your enemy.
  795. If stuck, ask on the mailing list, send your patches. Alot of time has been
  796. spent designing openais, and even more time debugging it. There are people
  797. that can help you debug problems, especially around things like message
  798. delivery.
  799. Submit patches early to get feedback, especially around things like parallel
  800. style. Parallel style is very important to ensure maintainability by the
  801. openais community.
  802. If this document is wrong or incomplete, complain so we can get it fixed
  803. for other people.
  804. Have fun!