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.


git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@2769 fd59a12c-fef9-0310-b244-a6a79926bd2f
This commit is contained in:
Jan Friesse 2010-04-20 10:32:07 +00:00
parent 2a12dafffb
commit da6fce352b
9 changed files with 895 additions and 74 deletions

View File

@ -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

View File

@ -1 +1 @@
4.1.0
4.2.0

352
lib/sam.c
View File

@ -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)

View File

@ -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 \

68
man/sam_data_getsize.3 Normal file
View File

@ -0,0 +1,68 @@
.\"/*
.\" * Copyright (c) 2010 Red Hat, Inc.
.\" *
.\" * All rights reserved.
.\" *
.\" * Author: Jan Friesse (jfriesse@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)

77
man/sam_data_restore.3 Normal file
View File

@ -0,0 +1,77 @@
.\"/*
.\" * Copyright (c) 2010 Red Hat, Inc.
.\" *
.\" * All rights reserved.
.\" *
.\" * Author: Jan Friesse (jfriesse@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)

83
man/sam_data_store.3 Normal file
View File

@ -0,0 +1,83 @@
.\"/*
.\" * Copyright (c) 2010 Red Hat, Inc.
.\" *
.\" * All rights reserved.
.\" *
.\" * Author: Jan Friesse (jfriesse@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)

View File

@ -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),

View File

@ -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)
{
printf ("%s %d\n", __FUNCTION__, ++test4_hc_cb_count);
size_t size;
cs_error_t err;
int i;
unsigned int instance_id;
char saved_data[128];
char saved_data2[128];
if (test4_hc_cb_count > 10)
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 %zx\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 %zx\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 %zx\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 %zx\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 %zx\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 %zx\n", size);
return 1;
}
}
return (0);
}
static int test5_hc_cb (void)
{
printf ("%s %d\n", __FUNCTION__, ++test5_hc_cb_count);
sam_data_store (&test5_hc_cb_count, sizeof (test5_hc_cb_count));
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,14 @@ int main(int argc, char *argv[])
}
if (pid == 0) {
err = test3 ();
fprintf (stderr, "test3 %s\n", (err == 0 ? "passed" : "failed"));
if (err != 0)
all_passed = 0;
return err;
return (test3 ());
}
waitpid (pid, NULL, 0);
waitpid (pid, &stat, 0);
fprintf (stderr, "test3 %s\n", (WEXITSTATUS (stat) == 0 ? "passed" : "failed"));
if (WEXITSTATUS (stat) != 0)
all_passed = 0;
pid = fork ();
@ -404,15 +666,32 @@ int main(int argc, char *argv[])
}
if (pid == 0) {
err = test4 ();
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 ();
if (pid == -1) {
fprintf (stderr, "Can't fork\n");
return 1;
}
if (pid == 0) {
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");