From 717f368f86f160744e27a430d3b4ec2fd4c3bd64 Mon Sep 17 00:00:00 2001 From: Dmitri Pal Date: Thu, 3 Sep 2009 19:13:43 -0400 Subject: ELAPI Laying foundation for the async processing A relatively small patch aligning headers and a small portion of code for upcoming implementation of the async event processing. Cleanup of the test config file. --- common/elapi/elapi_async.h | 130 +++++++++++++++++++++++++--------- common/elapi/elapi_log.c | 45 +++++------- common/elapi/elapi_log.h | 5 +- common/elapi/elapi_priv.h | 64 ++++++++++++----- common/elapi/elapi_sink.h | 5 -- common/elapi/elapi_test/elapi_ut.conf | 16 ++++- 6 files changed, 175 insertions(+), 90 deletions(-) (limited to 'common') diff --git a/common/elapi/elapi_async.h b/common/elapi/elapi_async.h index 24cb7f8bc..f9fbd9e3c 100644 --- a/common/elapi/elapi_async.h +++ b/common/elapi/elapi_async.h @@ -22,51 +22,113 @@ #include -/* Signature ELAPI callback function that - * should be called when the event loop got an event on the - * socket or file descriptor. - * ELAPI will always try to write to sockets in async way - * if the sink has this capability. - * So this is the callback that will always be - * invoked when we get ACK from the process receiving events. +#define ELAPI_FD_READ 0x00000001 /* request to read */ +#define ELAPI_FD_WRITE 0x00000002 /* request to write */ + +/* Structure that holds ELAPI file descriptor's watch data */ +struct elapi_fd_data; + +/* Structure that holds ELAPI timer data */ +struct elapi_tm_data; + +/* Functions to set and get data from file descriptor data. */ +/* Functions return EINVAL if passed in argument is invalid. */ +int elapi_set_fd_priv(struct elapi_fd_data *fd_data, + void *priv_data_to_set); +int elapi_get_fd_priv(struct elapi_fd_data *fd_data, + void **priv_data_to_get); +/* Cleanup function */ +int elapi_destroy_fd_data(struct elapi_fd_data *fd_data); + +/* Functions to set and get custom data from timer data. */ +/* Functions return EINVAL if passed in argument is invalid. */ +int elapi_set_tm_priv(struct elapi_tm_data *tm_data, + void *priv_data_to_set); +int elapi_get_tm_priv(struct elapi_tm_data *tm_data, + void **priv_data_to_get); +/* Cleanup function */ +int elapi_destroy_tm_data(struct elapi_tm_data *tm_data); + +/* Public interfaces ELAPI exposes to handle fd or timer + * events (do not confuse with log events). + */ +int elapi_process_fd(struct elapi_fd_data *fd_data); +int elapi_process_tm(struct elapi_tm_data *tm_data); + +/* Signature of the function to add + * file descriptor into the event loop. + * Provided by caller of the ELAPI interface. */ -typedef int (*elapi_fd_callback)(int fd, /* File descriptor */ - void *elapi_data); /* ELAPI supplied data */ +typedef int (*elapi_add_fd)(int fd, + unsigned flags, + struct elapi_fd_data *fd_data, + void *ext_fd_data); -/* Signature ELAPI callback function that - * should be called when the event loop got a timer driven event. +/* Signature of the function to remove + * file descriptor from the event loop. + * Provided by caller of the ELAPI interface. */ -typedef int (*elapi_timer_callback)(void *elapi_data); /* ELAPI supplied data */ +typedef int (*elapi_rem_fd)(int fd, + struct elapi_fd_data *fd_data, + void *ext_fd_data); -/* Signature of the supplied by caller function that ELAPI - * will call to add the fd into the application event processing loop. +/* Signature of the function to set + * file descriptor for read/write operation. + * Provided by caller of the ELAPI interface. */ -typedef int (*elapi_add_fd)(int fd, /* File descriptor to add */ - void *callers_data, /* Data that the function - * would need to do its work */ - elapi_fd_callback handle, /* Callback to call when event happens */ - void *elapi_data); /* Data to pass to the callback */ - -/* Signature of the supplied by caller function that ELAPI - * will call to remove the fd from the application event processing loop. - * The implementation of the function should assume that - * ELAPI will close file/socket descriptor after colling this function. +typedef int (*elapi_set_fd)(int fd, + unsigned flags, + struct elapi_fd_data *fd_data, + void *ext_fd_data); + + +/* Signature of the function to add timer. + * Provided by caller of the ELAPI interface. + * Caller must be aware that the timeval strcuture + * is allocated on stack. */ -typedef int (*elapi_rem_fd)(int fd, /* File descriptor to add */ - void *callers_data); /* Data that the function - * would need to do its work */ +typedef int (*elapi_add_tm)(struct timeval *tv, + struct elapi_tm_data *tm_data, + void *ext_tm_data); -/* Signature of the supplied by caller function that ELAPI - * will call to add a new timer event to the application event processing loop. +/* Signature of the function to add timer. + * Provided by caller of the ELAPI interface. + * Caller must be aware that the timeval strcuture + * is allocated on stack. */ -typedef int (*elapi_add_timer)(struct timeval timer, /* Timer */ - void *callers_data, /* Data that the function - * would need to do its work */ - elapi_timer_callback handle, /* Callback to call when event happens */ - void *elapi_data); /* Data to pass to the callback */ +typedef int (*elapi_rem_tm)(struct elapi_tm_data *tm_data, + void *ext_tm_data); +/* Structure that contains the pointer to functions + * that needed to be provided to enable async processing. + */ +struct elapi_async_ctx { + elapi_add_fd add_fd_cb; + elapi_rem_fd rem_fd_cb; + elapi_set_fd set_fd_cb; + void *ext_fd_data; + elapi_add_tm add_tm_cb; + elapi_rem_tm rem_tm_cb; + void *ext_tm_data; +}; + +/* Interface to create the async context */ +int elapi_create_asctx(struct elapi_async_ctx **ctx, + elapi_add_fd add_fd_cb, + elapi_rem_fd rem_fd_cb, + elapi_set_fd set_fd_cb, + void *ext_fd_data, + elapi_add_tm add_tm_cb, + elapi_rem_tm rem_tm_cb, + void *ext_tm_data); + +/* Function to free the async context */ +void elapi_destroy_asctx(struct elapi_async_ctx *ctx); +/* Function to validate the consistency of the + * async context */ +int elapi_check_asctx(struct elapi_async_ctx *ctx); #endif diff --git a/common/elapi/elapi_log.c b/common/elapi/elapi_log.c index 67f6e3868..291527bf8 100644 --- a/common/elapi/elapi_log.c +++ b/common/elapi/elapi_log.c @@ -102,10 +102,7 @@ static int elapi_dsp_msg_with_vargs(uint32_t target, int elapi_create_dispatcher_adv(struct elapi_dispatcher **dispatcher, const char *appname, const char *config_path, - elapi_add_fd add_fd_add_fn, - elapi_rem_fd add_fd_rem_fn, - elapi_add_timer add_timer_fn, - void *callers_data) + struct elapi_async_ctx *async_ctx) { struct elapi_dispatcher *handle = NULL; struct collection_item *error_set = NULL; @@ -114,7 +111,6 @@ int elapi_create_dispatcher_adv(struct elapi_dispatcher **dispatcher, const char *config_file = NULL; const char *config_dir = NULL; struct stat stat_data; - int prm_cnt = 0; TRACE_FLOW_STRING("elapi_create_dispatcher_adv", "Entry point"); @@ -132,20 +128,7 @@ int elapi_create_dispatcher_adv(struct elapi_dispatcher **dispatcher, return EINVAL; } - /* Check that all the async data is present */ - if (add_fd_add_fn) prm_cnt++; - if (add_fd_rem_fn) prm_cnt++; - if (add_timer_fn) prm_cnt++; - if (callers_data) prm_cnt++; - - if ((prm_cnt > 0) && (prm_cnt < 4)) { - /* We got a mixture of NULLs and not NULLs. - * This is bad since all should be either provided - * or all should be NULL. - */ - TRACE_ERROR_STRING("Invalid sync parameters.", "At least one is NULL while others are not."); - return EINVAL; - } + /* FIXME: Check if context is valid */ /* Check what is passed in the config_path */ if (config_path) { @@ -264,13 +247,20 @@ int elapi_create_dispatcher_adv(struct elapi_dispatcher **dispatcher, } /* Populate async processing data if any */ - if (prm_cnt) { + if (async_ctx) { TRACE_INFO_STRING("Async data is present", ""); - handle->add_fd_add_fn = add_fd_add_fn; - handle->add_fd_rem_fn = add_fd_rem_fn; - handle->add_timer_fn = add_timer_fn; - handle->callers_data = callers_data; - handle->async_mode = 1; + handle->async_ctx = malloc(sizeof(struct elapi_async_ctx)); + if (handle->async_ctx != NULL) { + TRACE_ERROR_NUMBER("Failed to allocate async context", ENOMEM); + elapi_destroy_dispatcher(handle); + return ENOMEM; + } + /* Copy async data */ + memcpy(handle->async_ctx, async_ctx, sizeof(struct elapi_async_ctx)); + } + else { + TRACE_INFO_STRING("No async data present", ""); + handle->async_ctx = NULL; } *dispatcher = handle; @@ -293,9 +283,6 @@ int elapi_create_dispatcher(struct elapi_dispatcher **dispatcher, error = elapi_create_dispatcher_adv(dispatcher, appname, config_path, - NULL, - NULL, - NULL, NULL); TRACE_FLOW_STRING("elapi_create_dispatcher", "Exit."); @@ -335,6 +322,8 @@ void elapi_destroy_dispatcher(struct elapi_dispatcher *dispatcher) TRACE_INFO_STRING("Freeing application name.", ""); free(dispatcher->appname); + TRACE_INFO_STRING("Freeing async context.", ""); + free(dispatcher->async_ctx); TRACE_INFO_STRING("Freeing config.", ""); free_ini_config(dispatcher->ini_config); TRACE_INFO_STRING("Deleting targets name array.", ""); diff --git a/common/elapi/elapi_log.h b/common/elapi/elapi_log.h index 7d8a3b7d2..7d783553d 100644 --- a/common/elapi/elapi_log.h +++ b/common/elapi/elapi_log.h @@ -52,10 +52,7 @@ int elapi_create_dispatcher(struct elapi_dispatcher **dispatcher, /* Handle of int elapi_create_dispatcher_adv(struct elapi_dispatcher **dispatcher, /* Handle of the dispatcher will be stored in this variable */ const char *appname, /* Application name. Passed to the sinks to do initialization */ const char *config_path, /* See notes below in the elapi_init() function. */ - elapi_add_fd add_fd_add_fn, /* Caller's function to add file descriptor */ - elapi_rem_fd add_fd_rem_fn, /* Caller's function to remove file descriptor */ - elapi_add_timer add_timer_fn, /* Caller's function to add timer */ - void *callers_data); /* Data that needs to be passed when caller's callback is called. */ + struct elapi_async_ctx *async_ctx); /* Async context. */ /* Function to clean memory associated with the dispatcher */ void elapi_destroy_dispatcher(struct elapi_dispatcher *dispatcher); diff --git a/common/elapi/elapi_priv.h b/common/elapi/elapi_priv.h index 081fae8da..fb8cd3e85 100644 --- a/common/elapi/elapi_priv.h +++ b/common/elapi/elapi_priv.h @@ -61,17 +61,19 @@ /* Names of embedded providers */ #define ELAPI_EMB_PRVDR_FILE "file" -#define ELAPI_EMB_PRVDR_STDERR "stderr" #define ELAPI_EMB_PRVDR_SYSLOG "syslog" /* Numbers for embedded providers */ #define ELAPI_EMB_PRVDR_FILENUM 0 -#define ELAPI_EMB_PRVDR_STDERRNUM 1 -#define ELAPI_EMB_PRVDR_SYSLOGNUM 2 - +#define ELAPI_EMB_PRVDR_SYSLOGNUM 1 #define ELAPI_TARGET_ALL 0xFFFF /* 65k targets should be enough */ +/* Possible values for onerror config parameter */ +#define ELAPI_ONERROR_REVIVE 0 +#define ELAPI_ONERROR_DISABLE 1 + + struct elapi_dispatcher { /* Application name */ char *appname; @@ -88,11 +90,13 @@ struct elapi_dispatcher { /* Default event template */ struct collection_item *default_template; /* Async processing related data */ - elapi_add_fd add_fd_add_fn; - elapi_rem_fd add_fd_rem_fn; - elapi_add_timer add_timer_fn; - void *callers_data; + struct elapi_async_ctx *async_ctx; + /* Indicator of our synch mode + * FIXME: Do we need it? + */ uint32_t async_mode; + /* Time offset */ + int32_t offset; }; /* Structure to pass data from logging function to targets */ @@ -120,7 +124,7 @@ struct elapi_tgt_ctx { */ }; -/* FIXME: Compbine with context */ +/* Structure that hols sink's error status */ struct sink_status { int suspended; time_t lasttry; @@ -145,12 +149,20 @@ struct elapi_sink_ctx { struct collection_item *in_queue; /* Pending list */ struct collection_item *pending; - /* FIXME: add: - * sink's error status - */ + /* Sink's error status */ + struct sink_status status; + /* Synch/asynch mode */ uint32_t async_mode; /* Sink configuration data */ struct elapi_sink_cfg sink_cfg; + /* Back pointer to the target context. + * This is needed for the cases + * when we detect that sink + * is failed and we need + * to fail over for the next one. + */ + struct elapi_tgt_ctx *tgt_ctx; + }; /* The structure to hold the event and its context */ @@ -161,11 +173,31 @@ struct elapi_sink_ctx { * instead of the actual event. */ struct elapi_event_ctx { - struct collection_item *event; - /* FIXME: other things: - * time stamp - * resolved message + /* This is a copy of the event */ + /* We have to copy it for two reasons: + * a) It needs to be flattened so + * that we do not get unnecesary naming + * collisions if same key appears on different + * levels + * b) In case of async logging we need + * the original event until we are sure + * it is actually logged. If we do not + * keep it around the application can modify + * it or delete it before we figured out + * that sink is broken and we need to fail over. + * If in this case we go to another sink + * and if we do not have the original event + * we are screwed. */ + struct collection_item *event; + /* Reference count */ + int refcount; + /* Event time */ + time_t tm; + /* Resolved message */ + char *message; + /* Time offset */ + int32_t offset; }; /* Lookup structure for searching for providers */ diff --git a/common/elapi/elapi_sink.h b/common/elapi/elapi_sink.h index b72872136..03e681a51 100644 --- a/common/elapi/elapi_sink.h +++ b/common/elapi/elapi_sink.h @@ -32,11 +32,6 @@ #define SINK_ENTRY_POINT "get_sink_info" #define SINK_NAME_TEMPLATE "libelapi_sink_%s.so" -/* Flags related to loading sinks */ -#define SINK_FLAG_NO_LIMIT 0x00000000 /* NO limits to loading and manipulating this sink - default */ -#define SINK_FLAG_LOAD_SINGLE 0x00000001 /* Only allow one instance of the provider per process */ - - /* Log facility callbacks */ /* FIXME - the signatures need to take into the account async processing */ typedef int (*init_fn)(void **priv_ctx, diff --git a/common/elapi/elapi_test/elapi_ut.conf b/common/elapi/elapi_test/elapi_ut.conf index 00b5912a1..a42045a24 100644 --- a/common/elapi/elapi_test/elapi_ut.conf +++ b/common/elapi/elapi_test/elapi_ut.conf @@ -63,7 +63,6 @@ sinks = logfile, syslog ; ; Special sinks provided by ELAPI are: ; file -; stderr ; syslog ; ; Example: @@ -100,9 +99,9 @@ sinks = logfile, syslog ; of the sinks that act in the synch mode and guarantee ; the delivery or return failure. -; SPECIFIC FIELDS FOR DIFFERENT SINKS +; SPECIFIC CONFIGURATION PARAMETERS FOR DIFFERENT PROVIDERS ; -; 1) FILE SINK +; 1) FILE PROVIDER ; ; filename - name of the log file. If not specified .log will be used. ; Avoid using the same name of the file for different sinks, @@ -142,6 +141,17 @@ sinks = logfile, syslog ; If this value is missing or 0 - no flushing. ; If it is positive it denotes the number of events before next flush. ; If it is negative it denotes the number of seconds before next flush. +; Ignored if file is opened and closed each time. +; +; marker - (optional) +; Default is "\n". +; Marker specifies a line that will be inserted into the file to denote +; the beginning of a new run. The provided string is used as is +; as a format argument for the strftime() function. The string can +; contain zero or one time stamp format specifier listed in a man page +; for the strftime function(). Providing an invalid marker can +; potentially cause your application to crash. +; ; ; Format specific parameters: ; -- cgit