good for merge On Thu, 2010-04-15 at 14:22 +0200, Jan Friesse wrote: > Support for store user data in SAM > > Ability to in-memory storing of user data which survives between > instances of process. > > Also ability needed ability for bi-directional communication between > child and parent is added. > > Regards, > Honza > plain text document attachment (2010-04-15-sam-user-data-store.patch) > commit d6f2002ec4ce9384859e0952bffc72d677df9576 > Author: Jan Friesse <jfrie...@redhat.com> > Date: Thu Apr 15 14:18:53 2010 +0200 > > Support for store user data in SAM > > Ability to in-memory storing of user data which survives between > instances of process. > > Also ability needed ability for bi-directional communication between > child and parent is added. > > diff --git a/trunk/include/corosync/sam.h b/trunk/include/corosync/sam.h > index bf6b069..4e60e17 100644 > --- a/trunk/include/corosync/sam.h > +++ b/trunk/include/corosync/sam.h > @@ -160,6 +160,49 @@ cs_error_t sam_hc_send (void); > */ > cs_error_t sam_hc_callback_register (sam_hc_callback_t cb); > > +/* > + * Return size of stored data. > + * @param size Pointer to variable, where stored data size is returned. If > + * nothing or NULL is stored, then 0 is returned. > + * @return > + * - CS_OK in case no problem appeared > + * - CS_ERR_BAD_HANDLE in case you call this function before sam_init or > after > + * sam_finalize > + * - CS_ERR_INVALID_PARAM if size parameter is NULL > + */ > +cs_error_t sam_data_getsize (size_t *size); > + > +/* > + * Return stored data. > + * @param data Pointer to place, where to store data > + * @param size Allocated size of data > + * @return > + * - CS_OK if no problem appeared > + * - CS_ERR_BAD_HANDLE if you call this function before sam_init or after > sam_finalize > + * - CS_ERR_INVALID_PARAM if data is NULL or size is less then currently > saved user data length > + */ > +cs_error_t sam_data_restore ( > + void *data, > + size_t size); > + > +/* > + * Store user data. Such stored data survives restart of child. > + * @param data Data to store. You can use NULL to delete data > + * @param size Size of data to store. > + * @return > + * - CS_OK in case no problem appeared > + * - CS_ERR_BAD_HANDLE if you call this function before sam_init or > + * after sam_finalize > + * - CS_ERR_NO_MEMORY if data is too large and malloc/realloc was not > + * sucesfull > + * - CS_ERR_LIBRARY if some internal error appeared (communication with > parent > + * process) > + */ > +cs_error_t sam_data_store ( > + const void *data, > + size_t size); > + > + > #ifdef __cplusplus > } > #endif > diff --git a/trunk/lib/libsam.verso b/trunk/lib/libsam.verso > index ee74734..6aba2b2 100644 > --- a/trunk/lib/libsam.verso > +++ b/trunk/lib/libsam.verso > @@ -1 +1 @@ > -4.1.0 > +4.2.0 > diff --git a/trunk/lib/sam.c b/trunk/lib/sam.c > index 9487afd..207d4f9 100644 > --- a/trunk/lib/sam.c > +++ b/trunk/lib/sam.c > @@ -38,6 +38,7 @@ > > #include <config.h> > > +#include <limits.h> > #include <stdlib.h> > #include <string.h> > #include <unistd.h> > @@ -70,7 +71,13 @@ enum sam_internal_status_t { > enum sam_command_t { > SAM_COMMAND_START, > SAM_COMMAND_STOP, > - SAM_COMMAND_HB > + SAM_COMMAND_HB, > + SAM_COMMAND_DATA_STORE, > +}; > + > +enum sam_reply_t { > + SAM_REPLY_OK, > + SAM_REPLY_ERROR, > }; > > enum sam_parent_action_t { > @@ -85,14 +92,20 @@ static struct { > sam_recovery_policy_t recovery_policy; > enum sam_internal_status_t internal_status; > unsigned int instance_id; > - int parent_fd; > + int child_fd_out; > + int child_fd_in; > int term_send; > int warn_signal; > + int am_i_child; > > sam_hc_callback_t hc_callback; > pthread_t cb_thread; > int cb_rpipe_fd, cb_wpipe_fd; > int cb_registered; > + > + void *user_data; > + size_t user_data_size; > + size_t user_data_allocated; > } sam_internal_data; > > cs_error_t sam_initialize ( > @@ -115,6 +128,12 @@ cs_error_t sam_initialize ( > > sam_internal_data.warn_signal = SIGTERM; > > + sam_internal_data.am_i_child = 0; > + > + sam_internal_data.user_data = NULL; > + sam_internal_data.user_data_size = 0; > + sam_internal_data.user_data_allocated = 0; > + > return (CS_OK); > } > > @@ -132,7 +151,8 @@ static size_t sam_safe_write ( > bytes_write = 0; > > do { > - tmp_bytes_write = write (d, (const char *)buf + bytes_write, > nbyte - bytes_write); > + tmp_bytes_write = write (d, (const char *)buf + bytes_write, > + (nbyte - bytes_write > SSIZE_MAX) ? SSIZE_MAX : nbyte - > bytes_write); > > if (tmp_bytes_write == -1) { > if (!(errno == EAGAIN || errno == EINTR)) > @@ -142,7 +162,176 @@ static size_t sam_safe_write ( > } > } while (bytes_write != nbyte); > > - return bytes_write; > + return (bytes_write); > +} > + > +/* > + * Wrapper on top of read(2) function. It handles EAGAIN and EINTR states > and reads whole buffer if possible. > + */ > +static size_t sam_safe_read ( > + int d, > + void *buf, > + size_t nbyte) > +{ > + ssize_t bytes_read; > + ssize_t tmp_bytes_read; > + > + bytes_read = 0; > + > + do { > + tmp_bytes_read = read (d, (char *)buf + bytes_read, > + (nbyte - bytes_read > SSIZE_MAX) ? SSIZE_MAX : nbyte - > bytes_read); > + > + if (tmp_bytes_read == -1) { > + if (!(errno == EAGAIN || errno == EINTR)) > + return -1; > + } else { > + bytes_read += tmp_bytes_read; > + } > + > + } while (bytes_read != nbyte && tmp_bytes_read != 0); > + > + return (bytes_read); > +} > + > +cs_error_t sam_data_getsize (size_t *size) > +{ > + if (size == NULL) { > + return (CS_ERR_INVALID_PARAM); > + } > + > + if (sam_internal_data.internal_status != > SAM_INTERNAL_STATUS_INITIALIZED && > + sam_internal_data.internal_status != > SAM_INTERNAL_STATUS_REGISTERED && > + sam_internal_data.internal_status != > SAM_INTERNAL_STATUS_STARTED) { > + > + return (CS_ERR_BAD_HANDLE); > + } > + > + *size = sam_internal_data.user_data_size; > + > + return (CS_OK); > +} > + > +cs_error_t sam_data_restore ( > + void *data, > + size_t size) > +{ > + if (data == NULL) { > + return (CS_ERR_INVALID_PARAM); > + } > + > + if (sam_internal_data.internal_status != > SAM_INTERNAL_STATUS_INITIALIZED && > + sam_internal_data.internal_status != > SAM_INTERNAL_STATUS_REGISTERED && > + sam_internal_data.internal_status != > SAM_INTERNAL_STATUS_STARTED) { > + > + return (CS_ERR_BAD_HANDLE); > + } > + > + if (sam_internal_data.user_data_size == 0) { > + return (CS_OK); > + } > + > + if (size < sam_internal_data.user_data_size) { > + return (CS_ERR_INVALID_PARAM); > + } > + > + memcpy (data, sam_internal_data.user_data, > sam_internal_data.user_data_size); > + > + return (CS_OK); > +} > + > +cs_error_t sam_data_store ( > + const void *data, > + size_t size) > +{ > + cs_error_t err; > + char command; > + char *new_data; > + char reply; > + > + if (sam_internal_data.internal_status != > SAM_INTERNAL_STATUS_INITIALIZED && > + sam_internal_data.internal_status != > SAM_INTERNAL_STATUS_REGISTERED && > + sam_internal_data.internal_status != > SAM_INTERNAL_STATUS_STARTED) { > + > + return (CS_ERR_BAD_HANDLE); > + } > + > + if (sam_internal_data.user_data_allocated < size) { > + if ((new_data = realloc (sam_internal_data.user_data, size)) == > NULL) { > + return (CS_ERR_NO_MEMORY); > + } > + > + sam_internal_data.user_data_allocated = size; > + } else { > + new_data = sam_internal_data.user_data; > + } > + > + if (data == NULL) { > + size = 0; > + } > + > + if (sam_internal_data.am_i_child) { > + /* > + * We are child so we must send data to parent > + */ > + command = SAM_COMMAND_DATA_STORE; > + if (sam_safe_write (sam_internal_data.child_fd_out, &command, > sizeof (command)) != sizeof (command)) { > + return (CS_ERR_LIBRARY); > + } > + > + if (sam_safe_write (sam_internal_data.child_fd_out, &size, > sizeof (size)) != sizeof (size)) { > + return (CS_ERR_LIBRARY); > + } > + > + if (data != NULL && sam_safe_write > (sam_internal_data.child_fd_out, data, size) != size) { > + return (CS_ERR_LIBRARY); > + } > + > + /* > + * And wait for reply > + */ > + if (sam_safe_read (sam_internal_data.child_fd_in, &reply, > sizeof (reply)) != sizeof (reply)) { > + return (CS_ERR_LIBRARY); > + } > + > + switch (reply) { > + case SAM_REPLY_ERROR: > + /* > + * Read error and return that > + */ > + if (sam_safe_read (sam_internal_data.child_fd_in, &err, > sizeof (err)) != sizeof (err)) { > + return (CS_ERR_LIBRARY); > + } > + > + return (err); > + break; > + case SAM_REPLY_OK: > + /* > + * Everything correct > + */ > + break; > + default: > + return (CS_ERR_LIBRARY); > + break; > + } > + } > + > + /* > + * We are parent or we received OK reply from parent -> do required > action > + */ > + if (data == NULL) { > + free (sam_internal_data.user_data); > + sam_internal_data.user_data = NULL; > + sam_internal_data.user_data_allocated = 0; > + sam_internal_data.user_data_size = 0; > + } else { > + sam_internal_data.user_data = new_data; > + sam_internal_data.user_data_size = size; > + > + memcpy (sam_internal_data.user_data, data, size); > + } > + > + return (CS_OK); > } > > cs_error_t sam_start (void) > @@ -155,11 +344,11 @@ cs_error_t sam_start (void) > > command = SAM_COMMAND_START; > > - if (sam_safe_write (sam_internal_data.parent_fd, &command, 1) == -1) > + if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof > (command)) != sizeof (command)) > return (CS_ERR_LIBRARY); > > if (sam_internal_data.hc_callback) > - if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, 1) > == -1) > + if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, > sizeof (command)) != sizeof (command)) > return (CS_ERR_LIBRARY); > > sam_internal_data.internal_status = SAM_INTERNAL_STATUS_STARTED; > @@ -177,11 +366,11 @@ cs_error_t sam_stop (void) > > command = SAM_COMMAND_STOP; > > - if (sam_safe_write (sam_internal_data.parent_fd, &command, 1) == -1) > + if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof > (command)) != sizeof (command)) > return (CS_ERR_LIBRARY); > > if (sam_internal_data.hc_callback) > - if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, 1) > == -1) > + if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, > sizeof (command)) != sizeof (command)) > return (CS_ERR_LIBRARY); > > sam_internal_data.internal_status = SAM_INTERNAL_STATUS_REGISTERED; > @@ -199,7 +388,7 @@ cs_error_t sam_hc_send (void) > > command = SAM_COMMAND_HB; > > - if (sam_safe_write (sam_internal_data.parent_fd, &command, 1) == -1) > + if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof > (command)) != sizeof (command)) > return (CS_ERR_LIBRARY); > > return (CS_OK); > @@ -223,6 +412,8 @@ cs_error_t sam_finalize (void) > > sam_internal_data.internal_status = SAM_INTERNAL_STATUS_FINALIZED; > > + free (sam_internal_data.user_data); > + > exit_error: > return (CS_OK); > } > @@ -241,7 +432,69 @@ cs_error_t sam_warn_signal_set (int warn_signal) > return (CS_OK); > } > > -static enum sam_parent_action_t sam_parent_handler (int pipe_fd, pid_t > child_pid) > +static cs_error_t sam_parent_data_store ( > + int parent_fd_in, > + int parent_fd_out) > +{ > + char reply; > + char *user_data; > + ssize_t size; > + cs_error_t err; > + > + err = CS_OK; > + user_data = NULL; > + > + if (sam_safe_read (parent_fd_in, &size, sizeof (size)) != sizeof > (size)) { > + err = CS_ERR_LIBRARY; > + goto error_reply; > + } > + > + if (size > 0) { > + user_data = malloc (size); > + if (user_data == NULL) { > + err = CS_ERR_NO_MEMORY; > + goto error_reply; > + } > + > + if (sam_safe_read (parent_fd_in, user_data, size) != size) { > + err = CS_ERR_LIBRARY; > + goto free_error_reply; > + } > + } > + > + err = sam_data_store (user_data, size); > + if (err != CS_OK) { > + goto free_error_reply; > + } > + > + reply = SAM_REPLY_OK; > + if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof > (reply)) { > + err = CS_ERR_LIBRARY; > + goto free_error_reply; > + } > + > + free (user_data); > + > + return (CS_OK); > + > +free_error_reply: > + free (user_data); > +error_reply: > + reply = SAM_REPLY_ERROR; > + if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof > (reply)) { > + return (CS_ERR_LIBRARY); > + } > + if (sam_safe_write (parent_fd_out, &err, sizeof (err)) != sizeof (err)) > { > + return (CS_ERR_LIBRARY); > + } > + > + return (err); > +} > + > +static enum sam_parent_action_t sam_parent_handler ( > + int parent_fd_in, > + int parent_fd_out, > + pid_t child_pid) > { > int poll_error; > int action; > @@ -256,7 +509,7 @@ static enum sam_parent_action_t sam_parent_handler (int > pipe_fd, pid_t child_pid > action = SAM_PARENT_ACTION_CONTINUE; > > while (action == SAM_PARENT_ACTION_CONTINUE) { > - pfds.fd = pipe_fd; > + pfds.fd = parent_fd_in; > pfds.events = POLLIN; > pfds.revents = 0; > > @@ -309,7 +562,7 @@ static enum sam_parent_action_t sam_parent_handler (int > pipe_fd, pid_t child_pid > /* > * We have EOF or command in pipe > */ > - bytes_read = read (pipe_fd, &command, 1); > + bytes_read = sam_safe_read (parent_fd_in, &command, 1); > > if (bytes_read == 0) { > /* > @@ -324,37 +577,33 @@ static enum sam_parent_action_t sam_parent_handler (int > pipe_fd, pid_t child_pid > } > > if (bytes_read == -1) { > - /* > - * Something really bad happened in read side > - */ > - if (errno == EAGAIN || errno == EINTR) { > - continue; > - } > - > action = SAM_PARENT_ACTION_ERROR; > goto action_exit; > } > > /* > - * We have read command -> take status > + * We have read command > */ > - switch (status) { > - case 0: > - /* > - * Not started yet > - */ > - if (command == SAM_COMMAND_START) > + switch (command) { > + case SAM_COMMAND_START: > + if (status == 0) { > + /* > + * Not started yet > + */ > status = 1; > - break; > - > - case 1: > - /* > - * Started > - */ > - if (command == SAM_COMMAND_STOP) > + } > + break; > + case SAM_COMMAND_STOP: > + if (status == 1) { > + /* > + * Started > + */ > status = 0; > - break; > - > + } > + break; > + case SAM_COMMAND_DATA_STORE: > + sam_parent_data_store (parent_fd_in, > parent_fd_out); > + break; > } > } /* select_error > 0 */ > } /* action == SAM_PARENT_ACTION_CONTINUE */ > @@ -369,7 +618,7 @@ cs_error_t sam_register ( > cs_error_t error; > pid_t pid; > int pipe_error; > - int pipe_fd[2]; > + int pipe_fd_out[2], pipe_fd_in[2]; > enum sam_parent_action_t action; > int child_status; > > @@ -380,12 +629,15 @@ cs_error_t sam_register ( > error = CS_OK; > > while (1) { > - pipe_error = pipe (pipe_fd); > + if ((pipe_error = pipe (pipe_fd_out)) != 0) { > + error = CS_ERR_LIBRARY; > + goto error_exit; > + } > + > + if ((pipe_error = pipe (pipe_fd_in)) != 0) { > + close (pipe_fd_out[0]); > + close (pipe_fd_out[1]); > > - if (pipe_error != 0) { > - /* > - * Pipe creation error > - */ > error = CS_ERR_LIBRARY; > goto error_exit; > } > @@ -410,12 +662,16 @@ cs_error_t sam_register ( > /* > * Child process > */ > - close (pipe_fd[0]); > + close (pipe_fd_out[0]); > + close (pipe_fd_in[1]); > + > + sam_internal_data.child_fd_out = pipe_fd_out[1]; > + sam_internal_data.child_fd_in = pipe_fd_in[0]; > > - sam_internal_data.parent_fd = pipe_fd[1]; > if (instance_id) > *instance_id = sam_internal_data.instance_id; > > + sam_internal_data.am_i_child = 1; > sam_internal_data.internal_status = > SAM_INTERNAL_STATUS_REGISTERED; > > goto error_exit; > @@ -423,11 +679,13 @@ cs_error_t sam_register ( > /* > * Parent process > */ > - close (pipe_fd[1]); > + close (pipe_fd_out[1]); > + close (pipe_fd_in[0]); > > - action = sam_parent_handler (pipe_fd[0], pid); > + action = sam_parent_handler (pipe_fd_out[0], > pipe_fd_in[1], pid); > > - close (pipe_fd[0]); > + close (pipe_fd_out[0]); > + close (pipe_fd_in[1]); > > if (action == SAM_PARENT_ACTION_ERROR) { > error = CS_ERR_LIBRARY; > @@ -498,7 +756,7 @@ static void *hc_callback_thread (void *unused_param) > } > > if (poll_error > 0) { > - bytes_readed = read (sam_internal_data.cb_rpipe_fd, > &command, 1); > + bytes_readed = sam_safe_read > (sam_internal_data.cb_rpipe_fd, &command, 1); > > if (bytes_readed > 0) { > if (status == 0 && command == SAM_COMMAND_START) > diff --git a/trunk/man/Makefile.am b/trunk/man/Makefile.am > index da01c2e..5817a1a 100644 > --- a/trunk/man/Makefile.am > +++ b/trunk/man/Makefile.am > @@ -100,6 +100,9 @@ dist_man_MANS = \ > votequorum_qdisk_unregister.3 \ > votequorum_setexpected.3 \ > votequorum_setvotes.3 \ > + sam_data_getsize.3 \ > + sam_data_restore.3 \ > + sam_data_store.3 \ > sam_finalize.3 \ > sam_hc_callback_register.3 \ > sam_hc_send.3 \ > diff --git a/trunk/man/sam_data_getsize.3 b/trunk/man/sam_data_getsize.3 > new file mode 100644 > index 0000000..33d527e > --- /dev/null > +++ b/trunk/man/sam_data_getsize.3 > @@ -0,0 +1,68 @@ > +.\"/* > +.\" * Copyright (c) 2010 Red Hat, Inc. > +.\" * > +.\" * All rights reserved. > +.\" * > +.\" * Author: Jan Friesse (jfrie...@redhat.com) > +.\" * > +.\" * This software licensed under BSD license, the text of which follows: > +.\" * > +.\" * Redistribution and use in source and binary forms, with or without > +.\" * modification, are permitted provided that the following conditions are > met: > +.\" * > +.\" * - Redistributions of source code must retain the above copyright > notice, > +.\" * this list of conditions and the following disclaimer. > +.\" * - Redistributions in binary form must reproduce the above copyright > notice, > +.\" * this list of conditions and the following disclaimer in the > documentation > +.\" * and/or other materials provided with the distribution. > +.\" * - Neither the name of the Red Hat, Inc. nor the names of its > +.\" * contributors may be used to endorse or promote products derived from > this > +.\" * software without specific prior written permission. > +.\" * > +.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > "AS IS" > +.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, > THE > +.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > PURPOSE > +.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS > BE > +.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > +.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > +.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR > BUSINESS > +.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > +.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > +.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > +.\" * THE POSSIBILITY OF SUCH DAMAGE. > +.\" */ > +.TH "SAM_DATA_GETSIZE" 3 "04/15/2010" "corosync Man Page" "Corosync Cluster > Engine Programmer's Manual" > + > +.SH NAME > +.P > +sam_data_getsize \- Return size of stored data in bytes > + > +.SH SYNOPSIS > +.P > +\fB#include <corosync/sam.h>\fR > + > +.P > +\fBcs_error_t sam_data_getsize (size_t *\fIsize\fB);\fR > + > +.SH DESCRIPTION > +.P > +The \fBsam_data_getsize\fR function is used to return size of stored > +data. Size is returned in bytes. If user data is NULL, zero is returned. > +Function is intended to be used before \fBsam_data_restore(3)\fR call to > +properly allocate buffer for restored data. > + > +.SH RETURN VALUE > +.P > +This call return CS_OK value if successful, otherwise and error is returned. > + > +.SH ERRORS > +.TP > +CS_ERR_BAD_HANDLE > +component was not initialized by calling \fBsam_initialize(3)\fR or it was > finalized. > +.TP > +CS_ERR_INVALID_PARAM > +size parameter is NULL > + > +.SH "SEE ALSO" > +.BR sam_data_store (3), > +.BR sam_data_restore (3) > diff --git a/trunk/man/sam_data_restore.3 b/trunk/man/sam_data_restore.3 > new file mode 100644 > index 0000000..32b816a > --- /dev/null > +++ b/trunk/man/sam_data_restore.3 > @@ -0,0 +1,77 @@ > +.\"/* > +.\" * Copyright (c) 2010 Red Hat, Inc. > +.\" * > +.\" * All rights reserved. > +.\" * > +.\" * Author: Jan Friesse (jfrie...@redhat.com) > +.\" * > +.\" * This software licensed under BSD license, the text of which follows: > +.\" * > +.\" * Redistribution and use in source and binary forms, with or without > +.\" * modification, are permitted provided that the following conditions are > met: > +.\" * > +.\" * - Redistributions of source code must retain the above copyright > notice, > +.\" * this list of conditions and the following disclaimer. > +.\" * - Redistributions in binary form must reproduce the above copyright > notice, > +.\" * this list of conditions and the following disclaimer in the > documentation > +.\" * and/or other materials provided with the distribution. > +.\" * - Neither the name of the Red Hat, Inc. nor the names of its > +.\" * contributors may be used to endorse or promote products derived from > this > +.\" * software without specific prior written permission. > +.\" * > +.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > "AS IS" > +.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, > THE > +.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > PURPOSE > +.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS > BE > +.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > +.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > +.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR > BUSINESS > +.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > +.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > +.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > +.\" * THE POSSIBILITY OF SUCH DAMAGE. > +.\" */ > +.TH "SAM_DATA_RESTORE" 3 "04/15/2010" "corosync Man Page" "Corosync Cluster > Engine Programmer's Manual" > + > +.SH NAME > +.P > +sam_data_restore \- Restore previously saved user data > + > +.SH SYNOPSIS > +.P > +\fB#include <corosync/sam.h>\fR > + > +.P > +\fBcs_error_t sam_data_restore (void *\fIdata\fB, size_t \fIsize\fB);\fR > + > +.SH DESCRIPTION > +.P > +The \fBsam_data_restore\fR function is used to restore data, previously > +saved by calling \fBsam_data_store(3)\fR. Such data survives between > instances. > + > +.P > +The \fIdata\fR parameter is pointer to memory initialized by caller. Stored > data > +are copied there. This also means, that caller is responsible for freeing > memory. > + > +.P > +The \fIsize\fR parameter is length of \fIdata\fR. This one must be at least > same > +length as previously stored data otherwise error is returned. Parameter can > +be larger but only stored data size bytes are changed. > + > +Use \fBsam_data_getsize(3)\fR to find out length of stored data. > + > +.SH RETURN VALUE > +.P > +This call return CS_OK value if successful, otherwise and error is returned. > + > +.SH ERRORS > +.TP > +CS_ERR_BAD_HANDLE > +component was not initialized by calling \fBsam_initialize(3)\fR or it was > finalized. > +.TP > +CS_ERR_INVALID_PARAM > +data parameter is NULL or size is less then currently stored data length > + > +.SH "SEE ALSO" > +.BR sam_data_getsize (3), > +.BR sam_data_store (3) > diff --git a/trunk/man/sam_data_store.3 b/trunk/man/sam_data_store.3 > new file mode 100644 > index 0000000..6e90651 > --- /dev/null > +++ b/trunk/man/sam_data_store.3 > @@ -0,0 +1,83 @@ > +.\"/* > +.\" * Copyright (c) 2010 Red Hat, Inc. > +.\" * > +.\" * All rights reserved. > +.\" * > +.\" * Author: Jan Friesse (jfrie...@redhat.com) > +.\" * > +.\" * This software licensed under BSD license, the text of which follows: > +.\" * > +.\" * Redistribution and use in source and binary forms, with or without > +.\" * modification, are permitted provided that the following conditions are > met: > +.\" * > +.\" * - Redistributions of source code must retain the above copyright > notice, > +.\" * this list of conditions and the following disclaimer. > +.\" * - Redistributions in binary form must reproduce the above copyright > notice, > +.\" * this list of conditions and the following disclaimer in the > documentation > +.\" * and/or other materials provided with the distribution. > +.\" * - Neither the name of the Red Hat, Inc. nor the names of its > +.\" * contributors may be used to endorse or promote products derived from > this > +.\" * software without specific prior written permission. > +.\" * > +.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > "AS IS" > +.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, > THE > +.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR > PURPOSE > +.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS > BE > +.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR > +.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > +.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR > BUSINESS > +.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN > +.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) > +.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF > +.\" * THE POSSIBILITY OF SUCH DAMAGE. > +.\" */ > +.TH "SAM_DATA_STORE" 3 "04/15/2010" "corosync Man Page" "Corosync Cluster > Engine Programmer's Manual" > + > +.SH NAME > +.P > +sam_data_store \- Store user data > + > +.SH SYNOPSIS > +.P > +\fB#include <corosync/sam.h>\fR > + > +.P > +\fBcs_error_t sam_data_store (const void *\fIdata\fB, size_t \fIsize\fB);\fR > + > +.SH DESCRIPTION > +.P > +The \fBsam_data_store\fR function is used to store data, which survives > between > +instances. > + > +.P > +The \fIdata\fR parameter is pointer to memory with data to store. Data > +are stored in newly allocated memory inside library, so caller can safely > remove > +them after call of function. > + > +You can use NULL as parameter to remove and free previously saved data. In > this > +case \fIsize\fR argument is ignored. > + > +.P > +The \fIsize\fR parameter is length of \fIdata\fR. > + > +Use \fBsam_data_getsize(3)\fR to find out length of stored data and > \fBsam_data_restore(3)\fR > +to restore stored data. > + > +.SH RETURN VALUE > +.P > +This call return CS_OK value if successful, otherwise and error is returned. > + > +.SH ERRORS > +.TP > +CS_ERR_BAD_HANDLE > +component was not initialized by calling \fBsam_initialize(3)\fR or it was > finalized. > +.TP > +CS_ERR_NO_MEMORY > +internal malloc/realloc failed because data are too large > +.TP > +CS_ERR_LIBRARY > +some internal error appeared (mostly because communication with parent > process failed) > + > +.SH "SEE ALSO" > +.BR sam_data_getsize (3), > +.BR sam_data_restore (3) > diff --git a/trunk/man/sam_overview.8 b/trunk/man/sam_overview.8 > index 4547212..b670723 100644 > --- a/trunk/man/sam_overview.8 > +++ b/trunk/man/sam_overview.8 > @@ -115,9 +115,19 @@ or add timers to the active process to signal a > healthcheck operation is > successful. To use event driven healthchecking, > the \fBsam_hc_callback_register(3)\fR function should be executed. > > +.SH Storing user data > +.P > +Sometimes there is need to store some data, which survives between instances. > +One can in such case use files, databases, ... or much simpler in memory > solution > +presented by \fBsam_data_store(3)\fR, \fBsam_data_restore(3)\fR and > \fBsam_data_getsize(3)\fR > +functions. > + > .SH BUGS > .SH "SEE ALSO" > .BR sam_initialize (3), > +.BR sam_data_getsize (3), > +.BR sam_data_restore (3), > +.BR sam_data_store (3), > .BR sam_finalize (3), > .BR sam_start (3), > .BR sam_stop (3), > diff --git a/trunk/test/testsam.c b/trunk/test/testsam.c > index ae9a4cf..bb21169 100644 > --- a/trunk/test/testsam.c > +++ b/trunk/test/testsam.c > @@ -46,10 +46,11 @@ > #include <corosync/corotypes.h> > #include <corosync/sam.h> > #include <signal.h> > +#include <string.h> > #include <sys/wait.h> > > static int test2_sig_delivered = 0; > -static int test4_hc_cb_count = 0; > +static int test5_hc_cb_count = 0; > > /* > * First test will just register SAM, with policy restart. First instance > will > @@ -273,11 +274,262 @@ static int test3 (void) { > > } > > -static int test4_hc_cb (void) > +/* > + * Test sam_data_store, sam_data_restore and sam_data_getsize > + */ > +static int test4 (void) > +{ > + size_t size; > + cs_error_t err; > + int i; > + unsigned int instance_id; > + char saved_data[128]; > + char saved_data2[128]; > + > + printf ("%s: sam_data_getsize 1\n", __FUNCTION__); > + err = sam_data_getsize (&size); > + if (err != CS_ERR_BAD_HANDLE) { > + fprintf (stderr, "Test should return CS_ERR_BAD_HANDLE. Error > returned %d\n", err); > + return 1; > + } > + > + printf ("%s: sam_data_getsize 2\n", __FUNCTION__); > + err = sam_data_getsize (NULL); > + if (err != CS_ERR_INVALID_PARAM) { > + fprintf (stderr, "Test should return CS_ERR_INVALID_PARAM. > Error returned %d\n", err); > + return 1; > + } > + > + printf ("%s: sam_data_store 1\n", __FUNCTION__); > + err = sam_data_store (NULL, 0); > + if (err != CS_ERR_BAD_HANDLE) { > + fprintf (stderr, "Test should return CS_ERR_BAD_HANDLE. Error > returned %d\n", err); > + return 1; > + } > + > + printf ("%s: sam_data_restore 1\n", __FUNCTION__); > + err = sam_data_restore (saved_data, sizeof (saved_data)); > + if (err != CS_ERR_BAD_HANDLE) { > + fprintf (stderr, "Test should return CS_ERR_BAD_HANDLE. Error > returned %d\n", err); > + return 1; > + } > + > + printf ("%s: sam_initialize\n", __FUNCTION__); > + err = sam_initialize (0, SAM_RECOVERY_POLICY_RESTART); > + if (err != CS_OK) { > + fprintf (stderr, "Can't initialize SAM API. Error %d\n", err); > + return 1; > + } > + > + printf ("%s: sam_data_getsize 3\n", __FUNCTION__); > + err = sam_data_getsize (&size); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_ERR_BAD_HANDLE. Error > returned %d\n", err); > + return 1; > + } > + if (size != 0) { > + fprintf (stderr, "Test should return size of 0. Returned %x\n", > size); > + return 1; > + } > + > + printf ("%s: sam_data_restore 2\n", __FUNCTION__); > + err = sam_data_restore (NULL, sizeof (saved_data)); > + if (err != CS_ERR_INVALID_PARAM) { > + fprintf (stderr, "Test should return CS_ERR_INVALID_PARAM. > Error returned %d\n", err); > + return 1; > + } > + > + /* > + * Store some real data > + */ > + for (i = 0; i < sizeof (saved_data); i++) { > + saved_data[i] = (char)(i + 5); > + } > + > + printf ("%s: sam_data_store 2\n", __FUNCTION__); > + err = sam_data_store (saved_data, sizeof (saved_data)); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error returned > %d\n", err); > + return 1; > + } > + > + printf ("%s: sam_data_getsize 4\n", __FUNCTION__); > + err = sam_data_getsize (&size); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error returned > %d\n", err); > + return 1; > + } > + if (size != sizeof (saved_data)) { > + fprintf (stderr, "Test should return size of 0. Returned %x\n", > size); > + return 1; > + } > + > + printf ("%s: sam_data_restore 3\n", __FUNCTION__); > + err = sam_data_restore (saved_data2, sizeof (saved_data2) - 1); > + if (err != CS_ERR_INVALID_PARAM) { > + fprintf (stderr, "Test should return CS_ERR_INVALID_PARAM. > Error returned %d\n", err); > + return 1; > + } > + > + printf ("%s: sam_data_restore 4\n", __FUNCTION__); > + err = sam_data_restore (saved_data2, sizeof (saved_data2)); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error returned > %d\n", err); > + return 1; > + } > + > + if (memcmp (saved_data, saved_data2, sizeof (saved_data2)) != 0) { > + fprintf (stderr, "Retored data are not same\n"); > + return 1; > + } > + > + memset (saved_data2, 0, sizeof (saved_data2)); > + > + printf ("%s: sam_data_store 3\n", __FUNCTION__); > + err = sam_data_store (NULL, 1); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error returned > %d\n", err); > + return 1; > + } > + > + printf ("%s: sam_data_getsize 5\n", __FUNCTION__); > + err = sam_data_getsize (&size); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error returned > %d\n", err); > + return 1; > + } > + if (size != 0) { > + fprintf (stderr, "Test should return size of 0. Returned %x\n", > size); > + return 1; > + } > + > + printf ("%s: sam_data_store 4\n", __FUNCTION__); > + err = sam_data_store (saved_data, sizeof (saved_data)); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error returned > %d\n", err); > + return 1; > + } > + > + printf ("%s: register\n", __FUNCTION__); > + err = sam_register (&instance_id); > + if (err != CS_OK) { > + fprintf (stderr, "Can't register. Error %d\n", err); > + return 1; > + } > + > + if (instance_id == 1) { > + printf ("%s iid %d: sam_start\n", __FUNCTION__, instance_id); > + err = sam_start (); > + if (err != CS_OK) { > + fprintf (stderr, "Can't start hc. Error %d\n", err); > + return 1; > + } > + > + printf ("%s iid %d: sam_data_getsize 6\n", __FUNCTION__, > instance_id); > + err = sam_data_getsize (&size); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error > returned %d\n", err); > + return 1; > + } > + if (size != sizeof (saved_data2)) { > + fprintf (stderr, "Test should return size of 0. > Returned %x\n", size); > + return 1; > + } > + > + printf ("%s iid %d: sam_data_restore 5\n", __FUNCTION__, > instance_id); > + err = sam_data_restore (saved_data2, sizeof (saved_data2)); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error > returned %d\n", err); > + return 1; > + } > + > + if (memcmp (saved_data, saved_data2, sizeof (saved_data2)) != > 0) { > + fprintf (stderr, "Retored data are not same\n"); > + return 1; > + } > + > + for (i = 0; i < sizeof (saved_data); i++) { > + saved_data[i] = (char)(i - 5); > + } > + > + printf ("%s iid %d: sam_data_store 5\n", __FUNCTION__, > instance_id); > + err = sam_data_store (saved_data, sizeof (saved_data) - 7); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error > returned %d\n", err); > + return 1; > + } > + > + exit (1); > + } > + > + if (instance_id == 2) { > + printf ("%s iid %d: sam_start\n", __FUNCTION__, instance_id); > + err = sam_start (); > + if (err != CS_OK) { > + fprintf (stderr, "Can't start hc. Error %d\n", err); > + return 1; > + } > + > + printf ("%s iid %d: sam_data_getsize 7\n", __FUNCTION__, > instance_id); > + err = sam_data_getsize (&size); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error > returned %d\n", err); > + return 1; > + } > + if (size != sizeof (saved_data2) - 7) { > + fprintf (stderr, "Test should return size of 0. > Returned %x\n", size); > + return 1; > + } > + > + printf ("%s iid %d: sam_data_restore 6\n", __FUNCTION__, > instance_id); > + err = sam_data_restore (saved_data2, sizeof (saved_data2)); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error > returned %d\n", err); > + return 1; > + } > + > + for (i = 0; i < sizeof (saved_data); i++) { > + saved_data[i] = (char)(i - 5); > + } > + > + if (memcmp (saved_data, saved_data2, sizeof (saved_data2) - 7) > != 0) { > + fprintf (stderr, "Retored data are not same\n"); > + return 1; > + } > + > + printf ("%s iid %d: sam_data_store 6\n", __FUNCTION__, > instance_id); > + err = sam_data_store (NULL, 0); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error > returned %d\n", err); > + return 1; > + } > + > + exit (1); > + } > + > + if (instance_id == 3) { > + printf ("%s iid %d: sam_data_getsize 8\n", __FUNCTION__, > instance_id); > + err = sam_data_getsize (&size); > + if (err != CS_OK) { > + fprintf (stderr, "Test should return CS_OK. Error > returned %d\n", err); > + return 1; > + } > + if (size != 0) { > + fprintf (stderr, "Test should return size of 0. > Returned %x\n", size); > + return 1; > + } > + } > + > + return (0); > +} > + > +static int test5_hc_cb (void) > { > - printf ("%s %d\n", __FUNCTION__, ++test4_hc_cb_count); > + printf ("%s %d\n", __FUNCTION__, ++test5_hc_cb_count); > + > + sam_data_store (&test5_hc_cb_count, sizeof (test5_hc_cb_count)); > > - if (test4_hc_cb_count > 10) > + if (test5_hc_cb_count > 10) > return 1; > > return 0; > @@ -285,10 +537,11 @@ static int test4_hc_cb (void) > /* > * Test event driven healtchecking. > */ > -static int test4 (void) > +static int test5 (void) > { > cs_error_t error; > unsigned int instance_id; > + int hc_cb_count; > > printf ("%s: initialize\n", __FUNCTION__); > error = sam_initialize (100, SAM_RECOVERY_POLICY_RESTART); > @@ -305,7 +558,7 @@ static int test4 (void) > > if (instance_id == 1) { > printf ("%s iid %d: hc callback register\n", __FUNCTION__, > instance_id); > - error = sam_hc_callback_register (test4_hc_cb); > + error = sam_hc_callback_register (test5_hc_cb); > if (error != CS_OK) { > fprintf (stderr, "Can't register hc cb. Error %d\n", > error); > return 1; > @@ -326,12 +579,25 @@ static int test4 (void) > } > > if (instance_id == 2) { > + error = sam_data_restore (&hc_cb_count, sizeof (hc_cb_count)); > + if (error != CS_OK) { > + fprintf (stderr, "sam_data_restore should return CS_OK. > Error returned %d\n", error); > + return 1; > + } > + > + if (hc_cb_count != 11) { > + fprintf (stderr, "%s iid %d: Premature killed. > hc_cb_count should be 11 and it is %d\n", > + __FUNCTION__, instance_id - 1, hc_cb_count); > + return 1; > + > + } > return 0; > } > > return 1; > } > > + > int main(int argc, char *argv[]) > { > pid_t pid; > @@ -347,17 +613,14 @@ int main(int argc, char *argv[]) > } > > if (pid == 0) { > - err = test1 (); > - > - fprintf (stderr, "test1 %s\n", (err == 0 ? "passed" : > "failed")); > - if (err != 0) > - all_passed = 0; > - > - return err; > + return (test1 ()); > } > > - waitpid (pid, NULL, 0); > + waitpid (pid, &stat, 0); > > + fprintf (stderr, "test1 %s\n", (WEXITSTATUS (stat) == 0 ? "passed" : > "failed")); > + if (WEXITSTATUS (stat) != 0) > + all_passed = 0; > > pid = fork (); > > @@ -386,15 +649,31 @@ int main(int argc, char *argv[]) > } > > if (pid == 0) { > - err = test3 (); > + return (test3 ()); > + } > > - fprintf (stderr, "test3 %s\n", (err == 0 ? "passed" : > "failed")); > - if (err != 0) > - all_passed = 0; > - return err; > + waitpid (pid, &stat, 0); > + > + fprintf (stderr, "test3 %s\n", (WEXITSTATUS (stat) == 0 ? "passed" : > "failed")); > + if (WEXITSTATUS (stat) != 0) > + all_passed = 0; > + > + pid = fork (); > + > + if (pid == -1) { > + fprintf (stderr, "Can't fork\n"); > + return 1; > } > > - waitpid (pid, NULL, 0); > + if (pid == 0) { > + return (test4 ()); > + } > + > + waitpid (pid, &stat, 0); > + > + fprintf (stderr, "test4 %s\n", (WEXITSTATUS (stat) == 0 ? "passed" : > "failed")); > + if (WEXITSTATUS (stat) != 0) > + all_passed = 0; > > pid = fork (); > > @@ -404,15 +683,15 @@ int main(int argc, char *argv[]) > } > > if (pid == 0) { > - err = test4 (); > + err = test5 (); > > - fprintf (stderr, "test4 %s\n", (err == 0 ? "passed" : > "failed")); > - if (err != 0) > - all_passed = 0; > return err; > } > > - waitpid (pid, NULL, 0); > + waitpid (pid, &stat, 0); > + fprintf (stderr, "test5 %s\n", (WEXITSTATUS (stat) == 0 ? "passed" : > "failed")); > + if (WEXITSTATUS (stat) != 0) > + all_passed = 0; > > if (all_passed) > fprintf (stderr, "All tests passed\n"); > _______________________________________________ > Openais mailing list > Openais@lists.linux-foundation.org > https://lists.linux-foundation.org/mailman/listinfo/openais
_______________________________________________ Openais mailing list Openais@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/openais