Ack for patch 1,
You could use %PRIx64 for MDS addresses.
Mathi.
----- [email protected] wrote:
> osaf/services/saf/logsv/lgs/Makefile.am | 6 +-
> osaf/services/saf/logsv/lgs/lgs.h | 12 +
> osaf/services/saf/logsv/lgs/lgs_cb.h | 14 +
> osaf/services/saf/logsv/lgs/lgs_evt.cc | 66 ++-
> osaf/services/saf/logsv/lgs/lgs_evt.h | 5 +
> osaf/services/saf/logsv/lgs/lgs_file.cc | 5 +
> osaf/services/saf/logsv/lgs/lgs_file.h | 1 +
> osaf/services/saf/logsv/lgs/lgs_filehdl.cc | 424 ++++++++++++++++-
> osaf/services/saf/logsv/lgs/lgs_filehdl.h | 21 +
> osaf/services/saf/logsv/lgs/lgs_imm.cc | 541
> ++++++++++++++++++++-
> osaf/services/saf/logsv/lgs/lgs_main.cc | 134 ++++-
> osaf/services/saf/logsv/lgs/lgs_mbcsv.cc | 22 +-
> osaf/services/saf/logsv/lgs/lgs_recov.cc | 758
> +++++++++++++++++++++++++++++
> osaf/services/saf/logsv/lgs/lgs_recov.h | 37 +
> osaf/services/saf/logsv/lgs/lgs_stream.cc | 65 +-
> osaf/services/saf/logsv/lgs/lgs_stream.h | 28 +-
> osaf/services/saf/logsv/lgs/lgs_util.cc | 50 +-
> osaf/services/saf/logsv/lgs/lgs_util.h | 4 +
> 18 files changed, 2121 insertions(+), 72 deletions(-)
>
>
> The patch makes LOG service be able to handle the case that both SC
> nodes
> are down at the same time.
> When one or both nodes go up again the log service must be able to
> resume its work preferably without actions by the clients.
>
> A log client should not have to be aware of if one or both SC nodes
> are down.
> The only thing that should happen is that a TRY AGAIN (and in some
> cases TIMEOUT) returned.
> It is the responsibility of the client to decide how to handle this.
>
> diff --git a/osaf/services/saf/logsv/lgs/Makefile.am
> b/osaf/services/saf/logsv/lgs/Makefile.am
> --- a/osaf/services/saf/logsv/lgs/Makefile.am
> +++ b/osaf/services/saf/logsv/lgs/Makefile.am
> @@ -35,7 +35,8 @@ noinst_HEADERS = \
> lgs_mbcsv_v1.h \
> lgs_mbcsv_v2.h \
> lgs_mbcsv_v3.h \
> - lgs_mbcsv_v5.h
> + lgs_mbcsv_v5.h \
> + lgs_recov.h
>
> osaf_execbindir = $(pkglibdir)
> osaf_execbin_PROGRAMS = osaflogd
> @@ -63,7 +64,8 @@ osaflogd_SOURCES = \
> lgs_mbcsv_v1.cc \
> lgs_mbcsv_v2.cc \
> lgs_mbcsv_v3.cc \
> - lgs_mbcsv_v5.cc
> + lgs_mbcsv_v5.cc \
> + lgs_recov.cc
>
> osaflogd_LDADD = \
> $(top_builddir)/osaf/tools/safimm/src/libimmutil.la \
> diff --git a/osaf/services/saf/logsv/lgs/lgs.h
> b/osaf/services/saf/logsv/lgs/lgs.h
> --- a/osaf/services/saf/logsv/lgs/lgs.h
> +++ b/osaf/services/saf/logsv/lgs/lgs.h
> @@ -30,6 +30,8 @@
> #include <ncs_edu_pub.h>
> #include <ncs_util.h>
> #include <saAis.h>
> +#include <saf_error.h>
> +#include <saImmOm.h>
>
> /* LGS files */
> #include "lgsv_defs.h"
> @@ -111,6 +113,16 @@ extern void lgs_imm_impl_reinit_nonblock
> extern void lgs_imm_init_OI_handle(SaImmOiHandleT *immOiHandle,
> SaSelectionObjectT
> *immSelectionObject);
> extern void lgs_imm_impl_set(SaImmOiHandleT immOiHandle);
> +extern SaAisErrorT lgs_imm_init_configStreams(lgs_cb_t *cb);
>
> +// Functions for recovery handling
> +void lgs_clean_stream_objects(void);
> +void lgs_delete_one_stream_object(char *name_str);
> +void lgs_search_stream_objects(void);
> +SaUint32T *lgs_get_scAbsenceAllowed_attr(SaUint32T *attr_val);
> +int lgs_get_streamobj_attr(SaImmAttrValuesT_2 ***attrib_out,
> + char *object_name,
> + SaImmHandleT *immOmHandle);
> +int lgs_free_streamobj_attr(SaImmHandleT immHandle);
>
> #endif /* ifndef __LGS_H */
> diff --git a/osaf/services/saf/logsv/lgs/lgs_cb.h
> b/osaf/services/saf/logsv/lgs/lgs_cb.h
> --- a/osaf/services/saf/logsv/lgs/lgs_cb.h
> +++ b/osaf/services/saf/logsv/lgs/lgs_cb.h
> @@ -26,6 +26,14 @@
>
> #include "lgs_stream.h"
>
> +/* LGS Recovery states */
> +typedef enum {
> + LGS_NORMAL, /* No recovery is ongoing. All requests are
> handled normally */
> + LGS_RECOVERY /* Recover streams if in recovery list when
> stream open
> + * request with no parameters
> + */
> +} lgs_state_t;
> +
> /* Default HA state assigned locally during lgs initialization */
> #define LGS_HA_INIT_STATE 0
>
> @@ -87,6 +95,12 @@ typedef struct lgs_cb {
> LGA_DOWN_LIST *lga_down_list_tail;
>
> bool nid_started; /**< true if started by NID */
> + SaUint32T scAbsenceAllowed; /* OpenSAF global configuration for
> recovery handling */
> + lgs_state_t lgs_recovery_state; /* Indicate current recovery state
> for the server */
> +
> + // Initialize default value in contructor
> + lgs_cb() : lgs_recovery_state(LGS_NORMAL) {};
> +
> } lgs_cb_t;
>
> extern uint32_t lgs_cb_init(lgs_cb_t *);
> diff --git a/osaf/services/saf/logsv/lgs/lgs_evt.cc
> b/osaf/services/saf/logsv/lgs/lgs_evt.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_evt.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_evt.cc
> @@ -21,6 +21,7 @@
>
> #include "lgs_mbcsv_v1.h"
> #include "lgs_mbcsv_v2.h"
> +#include "lgs_recov.h"
>
> /* Macro to validate the version */
> #define m_LOG_VER_IS_VALID(ver) \
> @@ -375,6 +376,8 @@ static uint32_t proc_lga_updn_mds_msg(lg
> break;
>
> case LGSV_LGS_EVT_LGA_DOWN:
> + TRACE("%s: LGSV_LGS_EVT_LGA_DOWN mds_dest = %" PRIu64,
> + __FUNCTION__, evt->fr_dest);
> if ((lgs_cb->ha_state == SA_AMF_HA_ACTIVE) || (lgs_cb->ha_state
> ==
> SA_AMF_HA_QUIESCED)) {
> /* Remove this LGA entry from our processing lists */
> osaf_clock_gettime(CLOCK_REALTIME, &closetime_tspec);
> @@ -772,11 +775,17 @@ static uint32_t lgs_ckpt_stream_open(lgs
>
> /**
> * Create a new application stream
> - * @param open_sync_param
> - * @param o_stream
> - * @return
> + *
> + * @param open_sync_param[in] Parameters used to create the stream
> + * @param o_stream[out] The created stream
> + * @param create_object_f IMM stream object is created
> + *
> + * @return AIS return code
> */
> -static SaAisErrorT create_new_app_stream(lgsv_stream_open_req_t
> *open_sync_param, log_stream_t **o_stream)
> +SaAisErrorT create_new_app_stream(
> + lgsv_stream_open_req_t *open_sync_param,
> + log_stream_t **o_stream,
> + int creationFlag)
> {
> SaAisErrorT rc = SA_AIS_OK;
> log_stream_t *stream;
> @@ -870,7 +879,7 @@ static SaAisErrorT create_new_app_stream
> goto done;
> }
>
> - stream = log_stream_new(&open_sync_param->lstr_name,
> + stream = log_stream_new_1(&open_sync_param->lstr_name,
> open_sync_param->logFileName,
> open_sync_param->logFilePathName,
> open_sync_param->maxLogFileSize,
> @@ -878,7 +887,11 @@ static SaAisErrorT create_new_app_stream
> open_sync_param->logFileFullAction,
> open_sync_param->maxFilesRotated,
> open_sync_param->logFileFmt,
> - STREAM_TYPE_APPLICATION, STREAM_NEW,
> twelveHourModeFlag, 0);
> + STREAM_TYPE_APPLICATION,
> + STREAM_NEW,
> + twelveHourModeFlag,
> + 0,
> + creationFlag);
>
> if (stream == NULL) {
> rc = SA_AIS_ERR_NO_MEMORY;
> @@ -960,6 +973,7 @@ static uint32_t proc_stream_open_msg(lgs
> log_stream_t *logStream;
> char name[SA_MAX_NAME_LENGTH + 1];
> time_t file_closetime = 0;
> + int i_rc = 0;
>
> /* Create null-terminated stream name */
> memcpy(name, open_sync_param->lstr_name.value,
> open_sync_param->lstr_name.length);
> @@ -981,10 +995,12 @@ static uint32_t proc_stream_open_msg(lgs
> /* One of the well-known log streams */
> if (open_sync_param->lstr_open_flags &
> SA_LOG_STREAM_CREATE) {
> ais_rv = SA_AIS_ERR_INVALID_PARAM;
> + rc = NCSCC_RC_FAILURE;
> goto snd_rsp;
> }
> }
> } else {
> + /* Stream does not exist */
> if (cb->immOiHandle == 0) {
> TRACE("IMM service unavailable, open stream failed");
> ais_rv = SA_AIS_ERR_TRY_AGAIN;
> @@ -992,20 +1008,48 @@ static uint32_t proc_stream_open_msg(lgs
> }
>
> if ((open_sync_param->lstr_open_flags & SA_LOG_STREAM_CREATE)
> == 0)
> {
> - ais_rv = SA_AIS_ERR_NOT_EXIST;
> - goto snd_rsp;
> + /* The stream does not exist but the create flag is not
> + * set. If lgs_state is LGS_RECOVERY then:
> + * Check if the stream is in the list of stream objects
> + * not recovered. If in list, recover the stream and
> + * add it to the client
> + */
> + if (lgs_cb->lgs_recovery_state == LGS_RECOVERY) {
> + TRACE("%s LGS_RECOVERY",__FUNCTION__);
> + i_rc = lgs_restore_one_app_stream(name,
> + open_sync_param->client_id,
> + &logStream);
> + if (i_rc == -1) {
> + TRACE("%s lgs_restore_one_stream Fail",
> __FUNCTION__);
> + ais_rv = SA_AIS_ERR_NOT_EXIST;
> + goto snd_rsp;
> + }
> + TRACE("%s Stream %s is recovered",
> __FUNCTION__, name);
> + log_stream_print(logStream); /* TRACE */
> + lstr_id = logStream->streamId;
> + goto snd_rsp;
> + } else {
> + /* Trying to open a non existing stream */
> + TRACE("%s Attempt to open not existing stream",
> __FUNCTION__);
> + ais_rv = SA_AIS_ERR_NOT_EXIST;
> + goto snd_rsp;
> + }
> }
>
> /* Create the stream:
> * - Check parameters
> * - Create the stream in the stream "data base"
> * - If active create IMM runtime object
> + * - If recover do not create IMM object
> *
> * Note: Files are not created here
> */
> - ais_rv = create_new_app_stream(open_sync_param, &logStream);
> - if (ais_rv != SA_AIS_OK)
> + ais_rv = create_new_app_stream(open_sync_param, &logStream, 1);
> + if (ais_rv != SA_AIS_OK) {
> + TRACE("%s create_new_app_stream Fail \"%s\"",
> + __FUNCTION__, saf_error(ais_rv));
> goto snd_rsp;
> + }
> }
>
> /* Create the log files:
> @@ -1030,7 +1074,7 @@ static uint32_t proc_stream_open_msg(lgs
> goto snd_rsp;
> }
>
> - TRACE_4("logStream->streamId = %u", logStream->streamId);
> + TRACE_4("logStream->streamId = %u is created",
> logStream->streamId);
> lstr_id = logStream->streamId;
>
> snd_rsp:
> diff --git a/osaf/services/saf/logsv/lgs/lgs_evt.h
> b/osaf/services/saf/logsv/lgs/lgs_evt.h
> --- a/osaf/services/saf/logsv/lgs/lgs_evt.h
> +++ b/osaf/services/saf/logsv/lgs/lgs_evt.h
> @@ -77,4 +77,9 @@ extern uint32_t lgs_remove_lga_down_rec(
> extern void lgs_send_write_log_ack(uint32_t client_id, SaInvocationT
> invocation, SaAisErrorT error, MDS_DEST mds_dest);
> extern void lgs_free_write_log(const lgsv_write_log_async_req_t
> *param);
>
> +SaAisErrorT create_new_app_stream(
> + lgsv_stream_open_req_t *open_sync_param,
> + log_stream_t **o_stream,
> + int creationFlag);
> +
> #endif /*!LGS_EVT_H */
> diff --git a/osaf/services/saf/logsv/lgs/lgs_file.cc
> b/osaf/services/saf/logsv/lgs/lgs_file.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_file.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_file.cc
> @@ -184,6 +184,11 @@ static void *file_hndl_thread(void *nopa
> hndl_rc =
> own_log_files_by_group_hdl(lgs_com_data.indata_ptr,
> lgs_com_data.outdata_ptr,
> lgs_com_data.outdata_size);
> break;
> + case LGSF_GET_FILE_PAR:
> + hndl_rc =
> lgs_get_file_params_hdl(lgs_com_data.indata_ptr,
> +
> lgs_com_data.outdata_ptr,
> +
> lgs_com_data.outdata_size);
> + break;
> default:
> break;
> }
> diff --git a/osaf/services/saf/logsv/lgs/lgs_file.h
> b/osaf/services/saf/logsv/lgs/lgs_file.h
> --- a/osaf/services/saf/logsv/lgs/lgs_file.h
> +++ b/osaf/services/saf/logsv/lgs/lgs_file.h
> @@ -43,6 +43,7 @@ typedef enum {
> LGSF_CHECKPATH,
> LGSF_CHECKDIR,
> LGSF_OWN_LOGFILES,
> + LGSF_GET_FILE_PAR,
> LGSF_NOREQ
> }lgsf_treq_t;
>
> diff --git a/osaf/services/saf/logsv/lgs/lgs_filehdl.cc
> b/osaf/services/saf/logsv/lgs/lgs_filehdl.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_filehdl.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_filehdl.cc
> @@ -23,7 +23,6 @@
> #include <dirent.h>
> #include <fcntl.h>
> #include <sys/stat.h>
> -
> #include <unistd.h>
>
> #include <logtrace.h>
> @@ -731,3 +730,426 @@ done_exit:
> TRACE_LEAVE();
> return rc;
> }
> +
> +/*
> ****************************************************************************
> + * lgs_get_file_params_hdl() with help functions
> + *
> + * Find the file that was current log file before server down.
> + * Get file size
> + * Get last written record Id by reading the first characters of the
> last
> + * log record in the file
> + *
> + */
> +
> +/**
> + * Count the occurrences of character <c> in a string
> + * Count from end of string and stop when lim <c> is found or
> + * beginning of string
> + *
> + * @param str[in] '\0' terminated string to count characters in
> + * @param c[in] Character to count
> + * @param lim[in] Stop count when lim characters found
> + * @return number of occurrences
> + */
> +static int chr_cnt_b(char *str, char c, int lim)
> +{
> + int cnt = 0;
> +
> + if ((str == NULL) || (*str == '\0')) {
> + TRACE("%s: Parameter error", __FUNCTION__);
> + return 0;
> + }
> +
> + char *ptr_str_end = strchr(str, '\0');
> + char *ptr_str_pos = ptr_str_end - 1;
> +
> + while (1) {
> + if (*ptr_str_pos == c)
> + cnt++;
> +
> + /* End if beginning of file or char limit */
> + if ((ptr_str_pos == str) || (cnt >= lim))
> + break;
> +
> + ptr_str_pos--;
> + }
> +
> + return cnt;
> +}
> +
> +/**
> + * Filter function used by scandir.
> + * Find a current log file if it exist
> + * - name as in file_name_find[]
> + * - extension .log
> + * - two timestamps (other log files has four)
> + */
> +/* Filename prefix (no timestamps or extension */
> +static std::string file_name_find_g;
> +static int filter_logfile_name(const struct dirent *finfo)
> +{
> + bool name_found = false, ext_found = false;
> +
> + if (strstr(finfo->d_name, file_name_find_g.c_str()) != NULL)
> + name_found = true;
> + if (strstr(finfo->d_name, ".log") != NULL)
> + ext_found = true;
> +
> + return (int) (name_found && ext_found);
> +}
> +
> +/**
> + * Get name and size of log file containing the last record Id. Is
> current log
> + * file if not empty or last rotated if current log file is empty
> + * Also give name of current log file if exist
> + *
> + * @param filepath_i[in] Path to log file directory
> + * @param filename_i[in] Name prefix for file to search for
> + * @param filename_o[out] Name of file with Id. "" if no file
> found
> + * @param curname_o[out] Name of current log file or "" if no
> current found
> + * @param fsize[out] Size of current log file
> + * @return -1 on error filename_o is not valid
> + */
> +static int filename_get(
> + char *filepath_i, char *filename_i,
> + std::string &filename_o, std::string &curname_o,
> + uint32_t *fsize)
> +{
> + int rc = 0;
> + int num_files = 0;
> + int i = 0;
> + struct dirent **namelist;
> + struct stat statbuf;
> + std::string file_path;
> + double time_tmp;
> + char *str_p = NULL;
> + int len = 0;
> + /* Time newest file */
> + double time_new = 0;
> + /* Index in namelist for newest and second newest file */
> + int name_ix_prv = 0, name_ix_new = 0;
> + /* Set to true if file is empty */
> + bool empty_flg_prv = true, empty_flg_new = true;
> +
> + TRACE_ENTER();
> +
> + // /* Initiate out data */
> + filename_o.clear();
> + curname_o.clear();
> + *fsize = 0;
> +
> + /* Create a list of all .log files that has
> + * <filename_i> in <filepath_i>
> + */
> + file_name_find_g = filename_i;
> + num_files = scandir(filepath_i, &namelist, filter_logfile_name,
> alphasort);
> + if (num_files == -1) {
> + TRACE("%s: scandir Fail %s", __FUNCTION__, strerror(errno));
> + rc = -1;
> + goto done;
> + }
> +
> + if (num_files == 0) {
> + /* There is no log file at all */
> + TRACE("\t No log file at all found");
> + goto done_free;
> + }
> +
> + /* Special case, only one file is found
> + */
> + if (num_files == 1) {
> + file_path = std::string(filepath_i) + "/" + namelist[0]->d_name;
> + if (stat(file_path.c_str(), &statbuf) == -1) {
> + TRACE("%s: stat() Fail %s", __FUNCTION__,
> strerror(errno));
> + rc = -1;
> + goto done_free;
> + }
> +
> + /* Save found file name */
> + filename_o = namelist[0]->d_name;
> +
> + /* Handle current log file output */
> + goto done_hdl_cur;
> + }
> +
> + /* Find the newest and the second newest file in the list
> + * Return in filename_o name of newest file if not empty else
> + * the second newest (if that also is empty return error)
> + */
> + time_new = time_tmp = 0;
> + name_ix_prv = name_ix_new = 0;
> + empty_flg_prv = empty_flg_new = false;
> +
> + for (i = 0; i < num_files; i++) {
> + file_path = std::string(filepath_i) + "/" + namelist[i]->d_name;
> + if (stat(file_path.c_str(), &statbuf) == -1) {
> + TRACE("%s: stat() Fail %s", __FUNCTION__,
> strerror(errno));
> + rc = -1;
> + goto done_free;
> + }
> +
> + time_tmp = osaf_timespec_to_double(&statbuf.st_mtim);
> + if (time_tmp > time_new) {
> + name_ix_prv = name_ix_new;
> + name_ix_new = i;
> + time_new = time_tmp;
> + empty_flg_prv = empty_flg_new;
> + if (statbuf.st_size == 0)
> + empty_flg_new = true;
> + else
> + empty_flg_new = false;
> + }
> + }
> +
> + /* Give found filename for output */
> + *fsize = 0;
> + if (empty_flg_new == false) {
> + /* Give the newest filename and its size. File is not empty */
> + filename_o = namelist[name_ix_new]->d_name;
> + *fsize = statbuf.st_size;
> + } else if (empty_flg_prv == false) {
> + /* Give the second newest filename. File is not empty */
> + filename_o = namelist[name_ix_prv]->d_name;
> + } else {
> + /* Both files are empty. This is an error */
> + TRACE("%s: Both newest and second newest are empy",
> __FUNCTION__);
> + filename_o.clear();
> + rc = -1;
> + }
> +
> +done_hdl_cur:
> + /* Handle current log file output */
> + len = strlen(filename_i);
> + str_p = namelist[name_ix_new]->d_name + len;
> + if (chr_cnt_b(str_p, '_', 4) == 2) {
> + /* Newest is current log file */
> + curname_o = namelist[name_ix_new]->d_name;
> + }
> +
> +done_free:
> + /* Free namelist */
> + for (i = 0; i < num_files; i++) {
> + free(namelist[i]);
> + }
> +
> + free(namelist);
> +
> +done:
> + TRACE_LEAVE();
> + return rc;
> +}
> +
> +/**
> + * Get last record Id from the given file.
> + * Each record begins with a record Id number. The wanted Id is the
> last Id
> + * in the file
> + *
> + * @param file_name[in] Complete path to the file
> + * @return record Id or -1 on error. Set to 0 if no error but no Id
> is found
> + */
> +static int record_id_get(const char *file_path)
> +{
> + FILE *fd = NULL;
> + int id_rc = 0;
> + int i;
> + int c;
> + long endpos;
> +
> + char *read_line = NULL;
> + size_t dummy_n = 0;
> + ssize_t line_len;
> +
> + TRACE_ENTER();
> +
> + /* Open the file */
> + while (1) {
> + fd = fopen(file_path, "r");
> + if (fd != NULL) {
> + break;
> + } else if (errno != EINTR){
> + TRACE("%s fopen Fail %s",
> + __FUNCTION__, strerror(errno));
> + id_rc = -1;
> + goto done;
> + }
> + }
> +
> + /* Get last pos in file */
> + while(1) {
> + if (fseek(fd, 0, SEEK_END) == -1) {
> + if (errno == EINTR)
> + continue;
> + TRACE("\t %d fseek Fail %s",__LINE__, strerror(errno));
> + id_rc = -1;
> + goto done;
> + }
> + break;
> + }
> + endpos = ftell(fd);
> +
> + if (endpos == 0) {
> + /* The file is empty. No Id to find */
> + id_rc = 0;
> + goto done;
> + }
> +
> + /* Search from the end for '\n' (end of prev record)
> + * or beginning of file
> + */
> + for (i = 2; i < endpos; i++) {
> + while(1) {
> + if (fseek(fd, -i, SEEK_END) == -1) {
> + if (errno == EINTR)
> + continue;
> + TRACE("\t %d fseek Fail %s",
> + __LINE__, strerror(errno));
> + id_rc = -1;
> + goto done;
> + }
> + break;
> + }
> +
> + c = getc(fd);
> + if (c == '\n')
> + break;
> + }
> +
> + /* Get pos for line start */
> + c = getc(fd); /* Dummy read '\n' */
> +
> + /* Read the last record and get record id */
> + line_len = getline(&read_line, &dummy_n, fd);
> + if (line_len == -1) {
> + TRACE("%s: getline Fail %s",
> + __FUNCTION__, strerror(errno));
> + id_rc = -1;
> + goto done;
> + }
> + id_rc = atoi(read_line);
> + if (id_rc == 0) {
> + TRACE("%s: \"%s\" has no number. Id set to 0",
> + __FUNCTION__, read_line);
> + id_rc = 0;
> + goto done_free;
> + }
> +
> +done_free:
> + free(read_line);
> +
> +done:
> + if (fd != NULL)
> + fclose(fd);
> +
> + TRACE_LEAVE();
> + return id_rc;
> +}
> +
> +/**
> + * Get log file information:
> + * - Name of current log file: <name prefix>_YYMMDD_HHMMSS
> + * - Log record id
> + *
> + * Rules:
> + * - If current log file not empty: Name = cur log file, Size = file
> size,
> + * Id = fr file, rc = OK
> + * - If current log file empty no rotated: Name = cur log file, Size
> = 0,
> + * Id = 1, rc = OK
> + * - If current log file empty is rotated: Name = cur log file, Size
> = 0,
> + * Id = fr last rotated, rc =
> OK
> + * - If no log file at all: Name = NULL, Size = 0, Id = 1, rc = OK
> + * - If only rotated log file: Name = NULL, Size = 0, Id = fr rotated
> file,
> + * rc = OK
> + *
> + * @param indata[in] gfp_in_t
> + * file_name: File name prefix (name part before time stamps)
> + * file_path: Full path to directory root path + rel path
> + *
> + * @param outdata[out] gfp_out_t
> + * curFileName: Current file name <name prefix>_YYMMDD_HHMMSS
> + * curFileSize: Bytes written to current log file (file size)
> + * logRecordId: log record identifier for last written log
> record
> +
> + * @param max_outsize[in] sizeof gfp_out_t (not used)
> + *
> + * @return (-1) on error, out data not valid
> + */
> +int lgs_get_file_params_hdl(void *indata, void *outdata, size_t
> max_outsize)
> +{
> + gfp_in_t *par_in = static_cast<gfp_in_t *>(indata);
> + gfp_out_t *par_out = static_cast<gfp_out_t *>(outdata);
> + int rc = 0, int_rc = 0;
> + std::string file_name;
> + std::string file_name_cur;
> + std::string file_path;
> + int rec_id = 0;
> + char *ptr_str;
> +
> + uint32_t file_size = 0;
> +
> + TRACE_ENTER();
> +
> + osaf_mutex_unlock_ordie(&lgs_ftcom_mutex); /* UNLOCK Critical
> section */
> +
> + /* Initialize out parameters */
> + par_out->curFileName = NULL;
> + par_out->curFileSize = 0;
> + par_out->logRecordId = 0;
> +
> + /* Get log file to get info from and its size */
> + int_rc = filename_get(
> + par_in->file_path, par_in->file_name,
> + file_name, file_name_cur, &file_size
> + );
> + if (int_rc == -1) {
> + TRACE("%s: filename_get Fail",__FUNCTION__);
> + rc = -1;
> + goto done;
> + }
> +
> + if (file_name[0] == '\0') {
> + TRACE("No file found.");
> + rc = -1;
> + par_out->logRecordId = 0;
> + goto done;
> + }
> +
> + /* Create the file path */
> + file_path = std::string(par_in->file_path) + "/" + file_name;
> +
> + /* Find record id in file */
> + rec_id = record_id_get(file_path.c_str());
> + if (rec_id == -1) {
> + TRACE("%s: record_id_get Fail", __FUNCTION__);
> + rc = -1;
> + goto done;
> + }
> +
> + /* Fill in out data */
> + par_out->logRecordId = rec_id;
> + par_out->curFileSize = file_size;
> + if (file_name_cur.empty() == false) {
> + // This memory will be deleted in log_stream_open_file_restore()
> + // who wants to get the info from this memory -
> par_out->curFileName
> + par_out->curFileName = static_cast<char *>(
> + calloc(1, file_name_cur.size() + 1));
> + if (par_out->curFileName == NULL) {
> + LOG_ER("%s Failed to allocate memory", __FUNCTION__);
> + rc = -1;
> + goto done;
> + }
> +
> + strcpy(par_out->curFileName, file_name_cur.c_str());
> + /* Remove extension */
> + ptr_str = strstr(par_out->curFileName, ".log");
> + if (ptr_str == NULL) {
> + TRACE("%s: Could not find .log extension Fail",
> __FUNCTION__);
> + rc = -1;
> + }
> + *ptr_str = '\0';
> + }
> +
> +done:
> + osaf_mutex_lock_ordie(&lgs_ftcom_mutex); /* LOCK after critical
> section */
> + TRACE_LEAVE2("rc = %d", rc);
> + return rc;
> +}
> diff --git a/osaf/services/saf/logsv/lgs/lgs_filehdl.h
> b/osaf/services/saf/logsv/lgs/lgs_filehdl.h
> --- a/osaf/services/saf/logsv/lgs/lgs_filehdl.h
> +++ b/osaf/services/saf/logsv/lgs/lgs_filehdl.h
> @@ -155,6 +155,26 @@ typedef struct {
> * No out parameters
> */
>
> +/*
> + * lgs_get_file_params_hdl(...)
> + * Ret code -1 if error
> + */
> +/* IN params */
> +typedef struct {
> + /* File name prefix (name part before time stamps) */
> + char *file_name;
> + /* Full path to directory root path + rel path */
> + char *file_path;
> +} gfp_in_t;
> +
> +/* OUT params */
> +typedef struct {
> + char *curFileName;
> + uint32_t curFileSize; /* Bytes written to current log file */
> + uint32_t logRecordId; /* log record identifier increased for each
> record */
> +} gfp_out_t;
> +
> +
> int path_is_writeable_dir_hdl(void *indata, void *outdata, size_t
> max_outsize);
> int check_path_exists_hdl(void *indata, void *outdata, size_t
> max_outsize);
> int rename_file_hdl(void *indata, void *outdata, size_t
> max_outsize);
> @@ -166,6 +186,7 @@ int fileclose_hdl(void *indata, void *ou
> int delete_file_hdl(void *indata, void *outdata, size_t
> max_outsize);
> int get_number_of_log_files_hdl(void *indata, void *outdata, size_t
> max_outsize);
> int own_log_files_by_group_hdl(void *indata, void *outdata, size_t
> max_outsize);
> +int lgs_get_file_params_hdl(void *indata, void *outdata, size_t
> max_outsize);
>
> #endif /* LGS_FILEHDL_H */
>
> diff --git a/osaf/services/saf/logsv/lgs/lgs_imm.cc
> b/osaf/services/saf/logsv/lgs/lgs_imm.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_imm.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_imm.cc
> @@ -42,6 +42,7 @@
> #include "lgs.h"
> #include "lgs_util.h"
> #include "lgs_file.h"
> +#include "lgs_recov.h"
> #include "lgs_config.h"
> #include "saf_error.h"
>
> @@ -2507,7 +2508,8 @@ done:
> * @return SaAisErrorT
> */
> static SaAisErrorT stream_create_and_configure(const char *dn,
> - log_stream_t **in_stream, int stream_id, SaImmAccessorHandleT
> accessorHandle)
> + log_stream_t **in_stream, int stream_id,
> + SaImmAccessorHandleT accessorHandle)
> {
> SaAisErrorT rc = SA_AIS_OK;
> SaNameT objectName;
> @@ -2606,6 +2608,15 @@ static SaAisErrorT stream_create_and_con
> } else if (!strcmp(attribute->attrName,
> "saLogStreamSeverityFilter")) {
> stream->severityFilter = *((SaUint32T *)value);
> TRACE("severityFilter: %u", stream->severityFilter);
> + } else if (!strcmp(attribute->attrName,
> "saLogStreamCreationTimestamp")) {
> + if (attribute->attrValuesNumber != 0) {
> + /* Restore creation timestamp if exist
> + * Note: Creation timestamp in stream is set to
> + * current time which will be the value if no
> + * value found in object
> + */
> + stream->creationTimeStamp =
> *(static_cast<SaTimeT *>(value));
> + }
> }
> }
>
> @@ -2648,11 +2659,15 @@ static const SaImmOiCallbacksT_2 callbac
> * IMM-OM interface and initialize the corresponding information
> * in the LOG control block. Initialize the LOG IMM-OI
> * interface. Become class implementer.
> + *
> + * @param immOiHandle[in]
> + * @return
> */
> -SaAisErrorT lgs_imm_create_configStream(lgs_cb_t *cb)
> +SaAisErrorT lgs_imm_init_configStreams(lgs_cb_t *cb)
> {
> - SaAisErrorT rc = SA_AIS_OK;
> + SaAisErrorT ais_rc = SA_AIS_OK;
> SaAisErrorT om_rc;
> + int int_rc = 0;
> log_stream_t *stream;
> SaImmHandleT omHandle;
> SaImmAccessorHandleT accessorHandle;
> @@ -2685,9 +2700,13 @@ SaAisErrorT lgs_imm_create_configStream(
> &immSearchHandle)) == SA_AIS_OK) {
>
> while (immutil_saImmOmSearchNext_2(immSearchHandle, &objectName,
> &attributes) == SA_AIS_OK) {
> - if ((rc = stream_create_and_configure((char*)
> objectName.value,
> - &stream, streamId, accessorHandle)) !=
> SA_AIS_OK) {
> - LOG_ER("stream_create_and_configure failed %d",
> rc);
> + /* Note: Here is creationTimeStamp and severityFilter
> set
> + * Can be recovered if scAbseceAllowed
> + */
> + ais_rc = stream_create_and_configure((char*)
> objectName.value,
> + &stream, streamId, accessorHandle);
> + if (ais_rc != SA_AIS_OK) {
> + LOG_WA("stream_create_and_configure failed %d",
> ais_rc);
> goto done;
> }
> streamId += 1;
> @@ -2709,12 +2728,35 @@ SaAisErrorT lgs_imm_create_configStream(
>
> stream = log_stream_getnext_by_name(NULL);
> while (stream != NULL) {
> - (void)immutil_update_one_rattr(cb->immOiHandle, stream->name,
> -
> const_cast<SaImmAttrNameT>("saLogStreamCreationTimestamp"),
> - SA_IMM_ATTR_SATIMET,
> - &stream->creationTimeStamp);
> -
> - log_stream_open_fileinit(stream);
> + if (cb->scAbsenceAllowed != 0) {
> + /**
> + * This code to make LOG distinguish b/w headless and
> cluster
> start-up/restarts
> + * 1) If data reading from IMM differs with default
> ones, headless
> just occurs
> + * 2) If data reading from IMM equals to default ones,
> continue
> checking:
> + * 2.1) If info in cfg file are equal to data reading
> from IMM,
> can reuse the cfg/log files
> + * 2.2) If info in cfg are not equal to, can not
> re-use cfg/log
> file. Creating new ones instead.
> + */
> + int_rc = log_stream_open_file_restore(stream);
> + if (int_rc == -1) {
> + /* Restore failed. Initialize instead */
> + LOG_NO("%s: log_stream_open_file_restore Fail",
> __FUNCTION__);
> + log_stream_open_fileinit(stream);
> + stream->creationTimeStamp = lgs_get_SaTime();
> + }
> + } else {
> + /* Always create new files and set current timestamp to
> + * current time
> + */
> + log_stream_open_fileinit(stream);
> + stream->creationTimeStamp = lgs_get_SaTime();
> + }
> +
> + (void)immutil_update_one_rattr(
> + cb->immOiHandle, stream->name,
> +
> const_cast<SaImmAttrNameT>("saLogStreamCreationTimestamp"),
> + SA_IMM_ATTR_SATIMET,
> + &stream->creationTimeStamp);
> +
> stream = log_stream_getnext_by_name(stream->name);
> }
>
> @@ -2740,7 +2782,7 @@ SaAisErrorT lgs_imm_create_configStream(
> immutilWrapperProfile.errorsAreFatal = errorsAreFatal; /* Enable
> again */
>
> TRACE_LEAVE();
> - return rc;
> + return ais_rc;
> }
>
> /**
> @@ -2951,3 +2993,476 @@ void lgs_imm_impl_reinit_nonblocking(lgs
>
> TRACE_LEAVE();
> }
> +
> +/******************************************************************************
> + * Functions used for recovery handling
> +
> ******************************************************************************/
> +/**
> + * Search for old runtime stream objects and put their names in a
> list.
> + * Become OI for the runtime stream class if any objects found
> + *
> + * @param object_list
> + */
> +void lgs_search_stream_objects(void)
> +{
> + int rc = 0;
> + SaAisErrorT ais_rc = SA_AIS_OK;
> + SaImmHandleT immOmHandle;
> + SaImmSearchHandleT immSearchHandle;
> + const char* class_name = "SaLogStream";
> +
> + TRACE_ENTER();
> +
> + /* Save immutil settings and reconfigure immutil
> + */
> + struct ImmutilWrapperProfile tmp_immutilWrapperProfile;
> + tmp_immutilWrapperProfile.errorsAreFatal =
> immutilWrapperProfile.errorsAreFatal;
> + tmp_immutilWrapperProfile.nTries = immutilWrapperProfile.nTries;
> + tmp_immutilWrapperProfile.retryInterval =
> immutilWrapperProfile.retryInterval;
> +
> + immutilWrapperProfile.errorsAreFatal = 0;
> + immutilWrapperProfile.nTries = 500;
> + immutilWrapperProfile.retryInterval = 1000;
> +
> +
> + /* Intialize Om API
> + */
> + ais_rc = immutil_saImmOmInitialize(&immOmHandle, NULL,
> &immVersion);
> + if (ais_rc != SA_AIS_OK) {
> + LOG_WA("%s saImmOmInitialize FAIL %d", __FUNCTION__, ais_rc);
> + goto done;
> + }
> +
> + /* Initialize search for application stream runtime objects
> + * Search for all objects of class 'SaLogStream'
> + * Search criteria:
> + * Attribute SaImmAttrClassName == SaLogStream
> + */
> + SaImmSearchParametersT_2 searchParam;
> + searchParam.searchOneAttr.attrName = const_cast<char
> *>("SaImmAttrClassName");
> + searchParam.searchOneAttr.attrValueType = SA_IMM_ATTR_SASTRINGT;
> + searchParam.searchOneAttr.attrValue = &class_name;
> + SaNameT root_name;
> + root_name.value[0] = '\0';
> + root_name.length = 1;
> +
> + ais_rc = immutil_saImmOmSearchInitialize_2(
> + immOmHandle,
> + &root_name,
> + SA_IMM_SUBTREE,
> + SA_IMM_SEARCH_ONE_ATTR | SA_IMM_SEARCH_GET_NO_ATTR,
> + &searchParam,
> + NULL,
> + &immSearchHandle);
> + if (ais_rc != SA_AIS_OK) {
> + LOG_WA("%s saImmOmSearchInitialize FAIL %d", __FUNCTION__,
> ais_rc);
> + goto done_fin_Om;
> + }
> +
> + /* Iterate the search and save objects in list until all objects
> found
> + */
> + SaNameT object_name;
> + SaImmAttrValuesT_2 **attributes;
> +
> + ais_rc = immutil_saImmOmSearchNext_2(immSearchHandle, &object_name,
> &attributes);
> + if (ais_rc == SA_AIS_ERR_NOT_EXIST) {
> + TRACE("\tNo objects found");
> + }
> +
> + while (ais_rc == SA_AIS_OK) {
> + TRACE("\tFound object \"%s\"", reinterpret_cast<char
> *>(object_name.value));
> + /* Add the string to the list
> + */
> + rc = log_rtobj_list_add(reinterpret_cast<char
> *>(object_name.value));
> + if (rc == -1) {
> + TRACE("%s Could not add %s to list Fail",
> + __FUNCTION__, reinterpret_cast<char
> *>(object_name.value));
> + }
> +
> + /* Get next object */
> + ais_rc = immutil_saImmOmSearchNext_2(immSearchHandle,
> + &object_name, &attributes);
> + }
> + if (ais_rc == SA_AIS_ERR_NOT_EXIST) {
> + TRACE("\tAll objects found OK");
> + } else {
> + LOG_WA("\t%s saImmOmSearchNext FAILED %d", __FUNCTION__,
> ais_rc);
> + }
> +
> + /* Finalize the serach API
> + */
> + ais_rc = immutil_saImmOmSearchFinalize(immSearchHandle);
> + if (ais_rc != SA_AIS_OK) {
> + TRACE("\tsaImmOmSearchFinalize FAIL %d", ais_rc);
> + }
> +
> +done_fin_Om:
> + /* Finalize the Om API
> + */
> + ais_rc = immutil_saImmOmFinalize(immOmHandle);
> + if (ais_rc != SA_AIS_OK) {
> + TRACE("\tsaImmOmFinalize FAIL %d", ais_rc);
> + }
> +
> +done:
> + /* Restore immutil settings */
> + immutilWrapperProfile.errorsAreFatal =
> tmp_immutilWrapperProfile.errorsAreFatal;
> + immutilWrapperProfile.nTries = tmp_immutilWrapperProfile.nTries;
> + immutilWrapperProfile.retryInterval =
> tmp_immutilWrapperProfile.retryInterval;
> +
> + TRACE_LEAVE();
> +}
> +
> +void lgs_delete_one_stream_object(char *name_str)
> +{
> + SaAisErrorT ais_rc = SA_AIS_OK;
> + SaNameT object_name;
> +
> + if (name_str == NULL) {
> + TRACE("%s No object name given", __FUNCTION__);
> + return;
> + }
> +
> + /* Save immutil settings and reconfigure */
> + struct ImmutilWrapperProfile tmp_immutilWrapperProfile;
> + tmp_immutilWrapperProfile.errorsAreFatal =
> immutilWrapperProfile.errorsAreFatal;
> + tmp_immutilWrapperProfile.nTries = immutilWrapperProfile.nTries;
> + tmp_immutilWrapperProfile.retryInterval =
> immutilWrapperProfile.retryInterval;
> +
> + immutilWrapperProfile.errorsAreFatal = 0;
> + immutilWrapperProfile.nTries = 500;
> + immutilWrapperProfile.retryInterval = 1000;
> +
> + /* Copy name to a SaNameT */
> + (void) strncpy(reinterpret_cast<char *>(object_name.value),
> + name_str, SA_MAX_NAME_LENGTH);
> + object_name.length = strlen(name_str) + 1;
> +
> + /* and delete the object */
> + ais_rc = immutil_saImmOiRtObjectDelete(lgs_cb->immOiHandle,
> &object_name);
> + if (ais_rc == SA_AIS_OK) {
> + TRACE("%s Object \"%s\" deleted", __FUNCTION__,
> + reinterpret_cast<char *>(object_name.value));
> + } else {
> + LOG_WA("%s saImmOiRtObjectDelete for \"%s\" FAILED %d",
> + __FUNCTION__, reinterpret_cast<char
> *>(object_name.value),
> ais_rc);
> + }
> +
> + /* Restore immutil settings */
> + immutilWrapperProfile.errorsAreFatal =
> tmp_immutilWrapperProfile.errorsAreFatal;
> + immutilWrapperProfile.nTries = tmp_immutilWrapperProfile.nTries;
> + immutilWrapperProfile.retryInterval =
> tmp_immutilWrapperProfile.retryInterval;
> +}
> +
> +/**
> + * Delete all stream objects in the stream object list.
> + * See also: lgs_search_stream_objects()
> + *
> + */
> +void lgs_clean_stream_objects(void)
> +{
> + SaAisErrorT ais_rc = SA_AIS_OK;
> + int pos = 0;
> + char *name_str;
> + SaNameT object_name;
> +
> + TRACE_ENTER();
> + /* Check if there are any objects to delete. If not do nothing */
> + if (log_rtobj_list_no() <= 0) {
> + TRACE("%s\t No objects to delete is found", __FUNCTION__);
> + return;
> + }
> +
> + /* Save immutil settings and reconfigure */
> + struct ImmutilWrapperProfile tmp_immutilWrapperProfile;
> + tmp_immutilWrapperProfile.errorsAreFatal =
> immutilWrapperProfile.errorsAreFatal;
> + tmp_immutilWrapperProfile.nTries = immutilWrapperProfile.nTries;
> + tmp_immutilWrapperProfile.retryInterval =
> immutilWrapperProfile.retryInterval;
> +
> + immutilWrapperProfile.errorsAreFatal = 0;
> + immutilWrapperProfile.nTries = 500;
> + immutilWrapperProfile.retryInterval = 1000;
> +
> + pos = log_rtobj_list_getnamepos();
> + while (pos != -1) {
> + /* Get found name */
> + name_str = log_rtobj_list_getname(pos);
> +
> + /* Delete the object if in object list. Note this is an Oi
> operation
> + * Remove name from list
> + */
> + if (name_str != NULL) {
> + /* Copy name to a SaNameT */
> + (void) strncpy(reinterpret_cast<char
> *>(object_name.value),
> + name_str, SA_MAX_NAME_LENGTH);
> + object_name.length = strlen(name_str) + 1;
> + /* and delete the object */
> + ais_rc =
> immutil_saImmOiRtObjectDelete(lgs_cb->immOiHandle,
> + &object_name);
> + if (ais_rc == SA_AIS_OK) {
> + TRACE("\tObject \"%s\" deleted",
> + reinterpret_cast<char
> *>(object_name.value));
> + } else {
> + LOG_WA("%s saImmOiRtObjectDelete for \"%s\"
> FAILED %d",
> + __FUNCTION__,
> + reinterpret_cast<char
> *>(object_name.value), ais_rc);
> + }
> + } else {
> + /* Should never happen! */
> + TRACE("%s\tFound name has NULL pointer!", __FUNCTION__);
> + }
> + /* Remove deleted object name from list */
> + log_rtobj_list_erase_one_pos(pos);
> +
> + /* Get next object */
> + pos = log_rtobj_list_getnamepos();
> + }
> +
> + /* Restore immutil settings */
> + immutilWrapperProfile.errorsAreFatal =
> tmp_immutilWrapperProfile.errorsAreFatal;
> + immutilWrapperProfile.nTries = tmp_immutilWrapperProfile.nTries;
> + immutilWrapperProfile.retryInterval =
> tmp_immutilWrapperProfile.retryInterval;
> +
> + TRACE_LEAVE();
> +}
> +
> +/**
> + * Get cached stream attributes for given object name
> + *
> + * @param attrib_out[out] Pointer to a NULL terminated
> SaImmAttrValuesT_2 vector
> + * @param object_name[in] String containing the object name
> + * @param immOmHandle[out]
> + * @return -1 on error
> + */
> +int lgs_get_streamobj_attr(SaImmAttrValuesT_2 ***attrib_out, char
> *object_name_in,
> + SaImmHandleT *immOmHandle)
> +{
> + int rc = 0;
> + SaAisErrorT ais_rc = SA_AIS_OK;
> + SaImmAccessorHandleT accessorHandle;
> + char *attribute_names[] = {
> + const_cast<char *>("saLogStreamFileName"),
> + const_cast<char *>("saLogStreamPathName"),
> + const_cast<char *>("saLogStreamMaxLogFileSize"),
> + const_cast<char *>("saLogStreamFixedLogRecordSize"),
> + const_cast<char *>("saLogStreamHaProperty"),
> + const_cast<char *>("saLogStreamLogFullAction"),
> + const_cast<char *>("saLogStreamMaxFilesRotated"),
> + const_cast<char *>("saLogStreamLogFileFormat"),
> + const_cast<char *>("saLogStreamSeverityFilter"),
> + const_cast<char *>("saLogStreamCreationTimestamp"),
> + NULL
> + };
> +
> + TRACE_ENTER2("object_name_in \"%s\"", object_name_in);
> +
> + SaNameT object_name;
> +
> + /* Save immutil settings and reconfigure */
> + struct ImmutilWrapperProfile tmp_immutilWrapperProfile;
> + tmp_immutilWrapperProfile.errorsAreFatal =
> immutilWrapperProfile.errorsAreFatal;
> + tmp_immutilWrapperProfile.nTries = immutilWrapperProfile.nTries;
> + tmp_immutilWrapperProfile.retryInterval =
> immutilWrapperProfile.retryInterval;
> +
> + immutilWrapperProfile.errorsAreFatal = 0;
> + immutilWrapperProfile.nTries = 500;
> + immutilWrapperProfile.retryInterval = 1000;
> +
> + if (object_name_in == NULL) {
> + TRACE("%s No object name given (NULL)", __FUNCTION__);
> + rc = -1;
> + goto done;
> + }
> +
> + /* Initialize Om API
> + */
> + ais_rc = immutil_saImmOmInitialize(immOmHandle, NULL, &immVersion);
> + if (ais_rc != SA_AIS_OK) {
> + LOG_WA("\t%s saImmOmInitialize FAIL %d", __FUNCTION__, ais_rc);
> + rc = -1;
> + goto done;
> + }
> +
> + /* Initialize accessor for reading attributes
> + */
> + ais_rc = immutil_saImmOmAccessorInitialize(*immOmHandle,
> &accessorHandle);
> + if (ais_rc != SA_AIS_OK) {
> + TRACE("%s\t saImmOmAccessorInitialize Fail '%s'",
> + __FUNCTION__, saf_error(ais_rc));
> + rc = -1;
> + goto done;
> + }
> +
> + strncpy(reinterpret_cast<char *>(object_name.value),
> + object_name_in, SA_MAX_NAME_LENGTH);
> + object_name.length = strlen(reinterpret_cast<char
> *>(object_name.value)) + 1;
> +
> + ais_rc = immutil_saImmOmAccessorGet_2(accessorHandle, &object_name,
> + attribute_names, attrib_out);
> + if (ais_rc != SA_AIS_OK) {
> + TRACE("%s\t saImmOmAccessorGet_2 Fail '%s'",
> + __FUNCTION__, saf_error(ais_rc));
> + rc = -1;
> + goto done_fin_Om;
> + } else {
> + goto done;
> + }
> +
> +done_fin_Om:
> + /* Free resources if fail */
> + ais_rc = immutil_saImmOmFinalize(*immOmHandle);
> + if (ais_rc != SA_AIS_OK) {
> + TRACE("%s\t saImmOmFinalize Fail '%s'",
> + __FUNCTION__, saf_error(ais_rc));
> + }
> +
> +done:
> + /* Restore immutil settings */
> + immutilWrapperProfile.errorsAreFatal =
> tmp_immutilWrapperProfile.errorsAreFatal;
> + immutilWrapperProfile.nTries = tmp_immutilWrapperProfile.nTries;
> + immutilWrapperProfile.retryInterval =
> tmp_immutilWrapperProfile.retryInterval;
> +
> + TRACE_LEAVE();
> + return rc;
> +}
> +
> +/**
> + * Free resources claimed when calling lgs_get_streamobj_attr()
> + *
> + * @param immHandle[in]
> + * @return -1 on error
> + */
> +int lgs_free_streamobj_attr(SaImmHandleT immOmHandle)
> +{
> + int rc = 0;
> + SaAisErrorT ais_rc = SA_AIS_OK;
> +
> + TRACE_ENTER();
> +
> + /* Save immutil settings and reconfigure */
> + struct ImmutilWrapperProfile tmp_immutilWrapperProfile;
> + tmp_immutilWrapperProfile.errorsAreFatal =
> immutilWrapperProfile.errorsAreFatal;
> + tmp_immutilWrapperProfile.nTries = immutilWrapperProfile.nTries;
> + tmp_immutilWrapperProfile.retryInterval =
> immutilWrapperProfile.retryInterval;
> +
> + immutilWrapperProfile.errorsAreFatal = 0;
> + immutilWrapperProfile.nTries = 500;
> + immutilWrapperProfile.retryInterval = 1000;
> +
> + ais_rc = immutil_saImmOmFinalize(immOmHandle);
> + if (ais_rc != SA_AIS_OK) {
> + TRACE("%s\t saImmOmFinalize Fail '%s'",
> + __FUNCTION__, saf_error(ais_rc));
> + rc = -1;
> + }
> +
> + /* Restore immutil settings */
> + immutilWrapperProfile.errorsAreFatal =
> tmp_immutilWrapperProfile.errorsAreFatal;
> + immutilWrapperProfile.nTries = tmp_immutilWrapperProfile.nTries;
> + immutilWrapperProfile.retryInterval =
> tmp_immutilWrapperProfile.retryInterval;
> +
> + TRACE_LEAVE();
> + return rc;
> +}
> +
> +/**
> + * Read the scAbsenceAllowed attribute in
> + * opensafImm=opensafImm,safApp=safImmService object.
> + * No value means that "absence handling" is not allowed. For Log
> this means
> + * that no recovery shall be done.
> + *
> + * @param attr_val[out] Value read from scAbsenceAllowed attribute. 0
> = No value
> + * @return Pointer to attr_val if value is read. NULL if no value. If
> NULL the
> + * value in attr_val is not valid
> + */
> +SaUint32T *lgs_get_scAbsenceAllowed_attr(SaUint32T *attr_val)
> +{
> + SaUint32T *rc_attr_val = NULL;
> + SaAisErrorT ais_rc = SA_AIS_OK;
> + SaImmAccessorHandleT accessorHandle;
> + SaImmHandleT immOmHandle;
> + SaImmAttrValuesT_2 *attribute;
> + SaImmAttrValuesT_2 **attributes;
> +
> + TRACE_ENTER();
> + char *attribute_names[] = {
> + const_cast<char *>("scAbsenceAllowed"),
> + NULL
> + };
> + char object_name_str[] =
> "opensafImm=opensafImm,safApp=safImmService";
> +
> + SaNameT object_name;
> + strncpy(reinterpret_cast<char *>(object_name.value),
> + object_name_str, SA_MAX_NAME_LENGTH);
> + object_name.length = strlen(reinterpret_cast<char
> *>(object_name.value)) + 1;
> +
> + /* Default restore handling shall be disabled. Is enabled if the
> + * scAbsenceAllowed attribute is not empty
> + */
> + *attr_val = 0;
> +
> + /* Save immutil settings and reconfigure */
> + struct ImmutilWrapperProfile tmp_immutilWrapperProfile;
> + tmp_immutilWrapperProfile.errorsAreFatal =
> immutilWrapperProfile.errorsAreFatal;
> + tmp_immutilWrapperProfile.nTries = immutilWrapperProfile.nTries;
> + tmp_immutilWrapperProfile.retryInterval =
> immutilWrapperProfile.retryInterval;
> +
> + immutilWrapperProfile.errorsAreFatal = 0;
> + immutilWrapperProfile.nTries = 500;
> + immutilWrapperProfile.retryInterval = 1000;
> +
> + /* Initialize Om API
> + */
> + ais_rc = immutil_saImmOmInitialize(&immOmHandle, NULL,
> &immVersion);
> + if (ais_rc != SA_AIS_OK) {
> + LOG_WA("\t%s saImmOmInitialize FAIL %d", __FUNCTION__, ais_rc);
> + goto done;
> + }
> +
> + /* Initialize accessor for reading attributes
> + */
> + ais_rc = immutil_saImmOmAccessorInitialize(immOmHandle,
> &accessorHandle);
> + if (ais_rc != SA_AIS_OK) {
> + TRACE("%s\t saImmOmAccessorInitialize Fail '%s'",
> + __FUNCTION__, saf_error(ais_rc));
> + goto done;
> + }
> +
> +
> + ais_rc = immutil_saImmOmAccessorGet_2(accessorHandle, &object_name,
> + attribute_names, &attributes);
> + if (ais_rc != SA_AIS_OK) {
> + TRACE("%s\t saImmOmAccessorGet_2 Fail '%s'",
> + __FUNCTION__, saf_error(ais_rc));
> + goto done_fin_Om;
> + }
> +
> + void *value;
> +
> + /* Handle the global scAbsenceAllowed_flag */
> + attribute = attributes[0];
> + TRACE("%s\t attrName \"%s\"", __FUNCTION__, attribute->attrName);
> + if ((attribute != NULL) && (attribute->attrValuesNumber != 0)) {
> + /* scAbsenceAllowed has value. Get the value */
> + value = attribute->attrValues[0];
> + *attr_val = *(static_cast<SaUint32T *>(value));
> + rc_attr_val = attr_val;
> + }
> +
> +done_fin_Om:
> + /* Free Om resources */
> + ais_rc = immutil_saImmOmFinalize(immOmHandle);
> + if (ais_rc != SA_AIS_OK) {
> + TRACE("%s\t saImmOmFinalize Fail '%s'",
> + __FUNCTION__, saf_error(ais_rc));
> + }
> +
> +done:
> + /* Restore immutil settings */
> + immutilWrapperProfile.errorsAreFatal =
> tmp_immutilWrapperProfile.errorsAreFatal;
> + immutilWrapperProfile.nTries = tmp_immutilWrapperProfile.nTries;
> + immutilWrapperProfile.retryInterval =
> tmp_immutilWrapperProfile.retryInterval;
> +
> + TRACE_LEAVE();
> + return rc_attr_val;
> +}
> diff --git a/osaf/services/saf/logsv/lgs/lgs_main.cc
> b/osaf/services/saf/logsv/lgs/lgs_main.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_main.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_main.cc
> @@ -31,21 +31,26 @@
> #include <daemon.h>
> #include <nid_api.h>
> #include <ncs_main_papi.h>
> +#include <osaf_time.h>
>
> #include "lgs.h"
> #include "lgs_file.h"
> #include "osaf_utility.h"
> +#include "lgs_recov.h"
>
> /*
> ========================================================================
> * DEFINITIONS
> *
> ========================================================================
> */
> -
> -#define FD_TERM 0
> -#define FD_AMF 1
> -#define FD_MBCSV 2
> -#define FD_MBX 3
> -#define FD_IMM 4 /* Must be the last in the fds array */
> +enum {
> + FD_TERM = 0,
> + FD_AMF,
> + FD_MBCSV,
> + FD_MBX,
> + FD_CLTIMER,
> + FD_IMM, /* Must be the last in the fds array */
> + FD_NUM
> +};
>
> #ifndef LOG_STREAM_LOW_LIMIT_PERCENT
> #define LOG_STREAM_LOW_LIMIT_PERCENT 0.6 // default value for low is
> 60%
> @@ -62,6 +67,7 @@
> */
>
> static lgs_cb_t _lgs_cb;
> +
> lgs_cb_t *lgs_cb = &_lgs_cb;
> SYSF_MBX lgs_mbx; /* LGS's mailbox */
>
> @@ -83,8 +89,8 @@ uint32_t mbox_low[NCS_IPC_PRIORITY_MAX];
> */
> pthread_mutex_t lgs_mbox_init_mutex = PTHREAD_MUTEX_INITIALIZER;
>
> -static struct pollfd fds[5];
> -static nfds_t nfds = 5;
> +static struct pollfd fds[FD_NUM];
> +static nfds_t nfds = FD_NUM;
> static NCS_SEL_OBJ usr1_sel_obj;
>
> /**
> @@ -195,6 +201,69 @@ uint32_t lgs_configure_mailbox(void)
> }
>
> /**
> + * Get OpenSAF global scAbsenceAllowed configuration
> + */
> +static void init_scAbsenceAllowed()
> +{
> + SaUint32T scAbsenceAllowed_val = 0;
> +
> + TRACE_ENTER();
> +
> + if (lgs_get_scAbsenceAllowed_attr(&scAbsenceAllowed_val) != NULL) {
> + TRACE("%s\t Got scAbsenceAllowed_val = %d", __FUNCTION__,
> + scAbsenceAllowed_val);
> + }
> +
> + lgs_cb->scAbsenceAllowed = scAbsenceAllowed_val;
> +
> + TRACE_LEAVE();
> +}
> +
> +/**
> + * Initiate recovery handling.
> + * Note1: This must be done during init before any streams are
> created
> + * Note2: Recovery state timer is started in the main() function
> + *
> + * If absence is allowed configuration is set:
> + * - Create a list of recoverable streams
> + * - If list is not empty set recovery state to LGS_RECOVERY
> + */
> +static void init_recovery()
> +{
> + int list_num = 0;
> +
> + TRACE_ENTER();
> +
> + /* Set default state */
> + lgs_cb->lgs_recovery_state = LGS_NORMAL;
> +
> + /* Get the value of the scAbsenceAllowed IMM attribute for
> configuring
> + * SC node absence handling
> + */
> + init_scAbsenceAllowed();
> +
> + if (lgs_cb->scAbsenceAllowed == 0) {
> + TRACE("%s Absence is not allowded", __FUNCTION__);
> + TRACE_LEAVE();
> + return;
> + }
> +
> + /* Create a list of recoverable (IMM object exist) streams */
> + lgs_search_stream_objects();
> + list_num = log_rtobj_list_no();
> +
> + TRACE("Number of runtime objects found = %d", list_num);
> +
> + /* set recovery state if the list is not empty */
> + if (list_num != 0) {
> + /* There are objects in list */
> + lgs_cb->lgs_recovery_state = LGS_RECOVERY;
> + }
> +
> + TRACE_LEAVE2();
> +}
> +
> +/**
> * Initialize log
> *
> * @return uns32
> @@ -254,6 +323,9 @@ static uint32_t log_initialize(void)
> goto done;
> }
>
> + /* Initiate "headless" recovery handling */
> + init_recovery();
> +
> /* Initialize configuration stream class
> * Configuration must have been initialized
> */
> @@ -324,7 +396,11 @@ static uint32_t log_initialize(void)
> /* Create streams that has configuration objects and become
> * class implementer for the SaLogStreamConfig class
> */
> - if (lgs_imm_create_configStream(lgs_cb) != SA_AIS_OK) {
> +
> + /* Note1: lgs_cb->immOiHandle is set in lgs_imm_init()
> + * Note2: lgs_cb->logsv_root_dir must be set
> + */
> + if (lgs_imm_init_configStreams(lgs_cb) != SA_AIS_OK) {
> LOG_ER("lgs_imm_create_configStream FAILED");
> rc = NCSCC_RC_FAILURE;
> goto done;
> @@ -362,6 +438,18 @@ int main(int argc, char *argv[])
> uint32_t rc;
> int term_fd;
>
> + /* File descriptor for timeout to delete not used stream runtime
> objects.
> + * May exist after 'headless' state.
> + */
> + int cltimer_fd = -1;
> +
> + /* Timeout time in seconds before clean up of runtime objects that
> may
> + * still exist after a "headless" situation. After timeout recovery
> of
> + * "lost" streams is no longer possible.
> + */
> + const time_t CLEAN_TIMEOUT = 600; /* 10 min */
> + //const time_t CLEAN_TIMEOUT = 60; /* 1 min LLDTEST */
> +
> daemonize(argc, argv);
>
> if (log_initialize() != NCSCC_RC_SUCCESS) {
> @@ -372,6 +460,13 @@ int main(int argc, char *argv[])
> mbx_fd = ncs_ipc_get_sel_obj(&lgs_mbx);
> daemon_sigterm_install(&term_fd);
>
> + if (log_rtobj_list_no() != 0) {
> + /* Needed only if any "lost" objects are found
> + * See log_initialize */
> + cltimer_fd = lgs_init_timer(CLEAN_TIMEOUT);
> + TRACE("%s Recovery timeout started", __FUNCTION__);
> + }
> +
> /* Set up all file descriptors to listen to */
> fds[FD_TERM].fd = term_fd;
> fds[FD_TERM].events = POLLIN;
> @@ -382,6 +477,8 @@ int main(int argc, char *argv[])
> fds[FD_MBCSV].events = POLLIN;
> fds[FD_MBX].fd = mbx_fd.rmv_obj;
> fds[FD_MBX].events = POLLIN;
> + fds[FD_CLTIMER].fd = cltimer_fd;
> + fds[FD_CLTIMER].events = POLLIN;
> fds[FD_IMM].fd = lgs_cb->immSelectionObject;
> fds[FD_IMM].events = POLLIN;
>
> @@ -440,6 +537,25 @@ int main(int argc, char *argv[])
> }
> }
>
> + if (fds[FD_CLTIMER].revents & POLLIN) {
> + /* To avoid 'stray objects', after a timeout all runtime
> + * objects that has not been restored shall be deleted
> + */
> + TRACE("Recover state End. Clean objects");
> +
> + /* Close timer to free resources and stop timer poll */
> + lgs_close_timer(cltimer_fd);
> + fds[FD_CLTIMER].fd = -1;
> +
> + if (lgs_cb->ha_state == SA_AMF_HA_ACTIVE) {
> + /* Delete objects left if active */
> + lgs_clean_stream_objects();
> + }
> +
> + /* Remove the found objects list */
> + log_rtobj_list_free();
> + }
> +
> if (fds[FD_MBX].revents & POLLIN)
> lgs_process_mbx(&lgs_mbx);
>
> diff --git a/osaf/services/saf/logsv/lgs/lgs_mbcsv.cc
> b/osaf/services/saf/logsv/lgs/lgs_mbcsv.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_mbcsv.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_mbcsv.cc
> @@ -24,6 +24,7 @@
> #include "lgs_mbcsv_v3.h"
> #include "lgs_mbcsv_v2.h"
> #include "lgs_mbcsv_v1.h"
> +#include "lgs_recov.h"
>
> /*
> LGS_CKPT_DATA_HEADER
> @@ -1856,6 +1857,7 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t
> {
> lgs_ckpt_stream_open_t *param;
> log_stream_t *stream;
> + int pos = 0;
>
> TRACE_ENTER();
>
> @@ -1871,7 +1873,8 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t
> /* Check that client still exist */
> if ((param->clientId != invalidClient) &&
> (lgs_client_get_by_id(param->clientId) == NULL)) {
> - LOG_WA("\tClient %u does not exist, failed to create stream
> '%s'",
> param->clientId, param->logStreamName);
> + LOG_WA("\tClient %u does not exist, failed to create stream
> '%s'",
> + param->clientId, param->logStreamName);
> goto done;
> }
>
> @@ -1890,7 +1893,7 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t
> strcpy((char *)name.value, param->logStreamName);
> name.length = strlen(param->logStreamName);
>
> - stream = log_stream_new(&name,
> + stream = log_stream_new_1(&name,
> param->logFile,
> param->logPath,
> param->maxFileSize,
> @@ -1901,11 +1904,12 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t
> param->streamType,
> param->streamId,
> SA_FALSE, // FIX sync or calculate?
> - param->logRecordId);
> + param->logRecordId,
> + 0);
>
> if (stream == NULL) {
> /* Do not allow standby to get out of sync */
> - LOG_ER("%s - Failed to create stream '%s'",__FUNCTION__,
> + LOG_ER("%s - Failed to create stream '%s'",
> __FUNCTION__,
> param->logStreamName);
> goto done;
> }
> @@ -1923,6 +1927,9 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t
> */
> if (lgs_is_split_file_system()) {
> if (stream->numOpeners <= 1) {
> + TRACE("%s: log_initiate_stream_files(%s)",
> + __FUNCTION__, stream->fileName.c_str());
> +
> log_initiate_stream_files(stream);
> }
> }
> @@ -1935,11 +1942,16 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t
> if ((param->clientId != invalidClient) &&
> lgs_client_stream_add(param->clientId, stream->streamId) != 0) {
> /* Do not allow standby to get out of sync */
> - LOG_ER("%s - Failed to add stream '%s' to client
> %u",__FUNCTION__,
> + LOG_ER("%s - Failed to add stream '%s' to client %u",
> __FUNCTION__,
> param->logStreamName, param->clientId);
> lgs_exit("Could not add stream to client",
> SA_AMF_COMPONENT_RESTART);
> }
>
> + /* Stream is opened on standby. Remove from rtobj list if exist */
> + pos = log_rtobj_list_find(param->logStreamName);
> + if (pos != -1)
> + log_rtobj_list_erase_one_pos(pos);
> +
> done:
> /* Free strings allocated by the EDU encoder */
> lgs_free_edu_mem(param->logFile);
> diff --git a/osaf/services/saf/logsv/lgs/lgs_recov.cc
> b/osaf/services/saf/logsv/lgs/lgs_recov.cc
> new file mode 100644
> --- /dev/null
> +++ b/osaf/services/saf/logsv/lgs/lgs_recov.cc
> @@ -0,0 +1,758 @@
> +/* -*- OpenSAF -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful,
> but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are
> licensed
> + * under the GNU Lesser General Public License Version 2.1, February
> 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for
> full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include "lgs_recov.h"
> +#include "lgs_file.h"
> +#include "lgs_filehdl.h"
> +
> +/***
> + * The following functions are used to handle a list of runtime
> stream objects
> + * (application streams with runtime objects) that may be found
> during start of
> + * the log server.
> + * The list consists of a vector of strings containing runtime stream
> object
> + * dn:s
> + */
> +
> +static char **rtobj_list = NULL;
> +static bool rtobj_list_init_f = false;
> +static uint32_t rtobj_cnt = 0; /* Number of object names in list */
> +static SaUint32T rtobj_list_len = 0; /* Also the length of the list
> */
> +
> +/**
> + * Initiate the list by allocating memory for a vector of pointers to
> strings
> + * (char *). The number of elements will be
> "logMaxApplicationStreams", see log
> + * configuration object.
> + *
> + * @return true if initiated (list exist)
> + */
> +static bool log_rtobj_list_init()
> +{
> + TRACE_ENTER();
> +
> + if (rtobj_list_init_f == true)
> + goto done; /* Already initiated */
> +
> + rtobj_list_len = *static_cast<const SaUint32T *>(
> + lgs_cfg_get(LGS_IMM_LOG_MAX_APPLICATION_STREAMS));
> +
> + rtobj_list = static_cast<char **>(calloc(rtobj_list_len, sizeof(char
> *)));
> + if (rtobj_list != NULL) {
> + rtobj_list_init_f = true;
> + } else {
> + TRACE("%s\tFail to alloc memory for rtobj_list", __FUNCTION__);
> + }
> +
> +done:
> + TRACE_LEAVE2("rtobj_list_init_f = %d", rtobj_list_init_f);
> + return rtobj_list_init_f;
> +}
> +
> +/**
> + * Free an initialized rtobj list
> + *
> + */
> +void log_rtobj_list_free()
> +{
> + TRACE_ENTER();
> +
> + if (rtobj_list == NULL)
> + return; /* No list to free */
> +
> + /* Free positions in the list if needed */
> + uint32_t pos;
> + for (pos = 0; pos < rtobj_list_len; pos++) {
> + if (rtobj_list[pos] != NULL)
> + free(rtobj_list[pos]);
> + }
> +
> + free(rtobj_list);
> + rtobj_cnt = 0;
> + rtobj_list_len = 0;
> + rtobj_list = NULL;
> +
> + TRACE_LEAVE();
> +}
> +
> +/**
> + * Add a dn name of an rt-object
> + *
> + * @param dn_str[in] '\0' terminated string containing a dn
> + * @return -1 on error
> + */
> +int log_rtobj_list_add(char *dn_str)
> +{
> + char *str_ptr = NULL;
> + size_t len = 0;
> + int rc = 0;
> +
> + TRACE_ENTER();
> +
> + if (log_rtobj_list_init() == false) {
> + TRACE("%s\trtobj_list not initiated!", __FUNCTION__);
> + rc = -1;
> + goto done;
> + }
> +
> + if (rtobj_cnt >= rtobj_list_len) {
> + /* Should be impossible */
> + LOG_WA("%s\trtobj_cnt >= maxApplicationStreams!",
> + __FUNCTION__);
> + rc = -1;
> + goto done;
> + }
> +
> + /* Save dn string */
> + len = strlen(dn_str) + 1; /* Including '\0' */
> + if (len > SA_MAX_NAME_LENGTH) {
> + /* Should never happen */
> + LOG_WA("%s\tToo long dn string!",__FUNCTION__);
> + rc = -1;
> + goto done;
> + }
> +
> + str_ptr = static_cast<char *>(calloc(1, len));
> + if (str_ptr == NULL) {
> + LOG_WA("%s\tcalloc Fail",__FUNCTION__);
> + rc = -1;
> + goto done;
> + }
> +
> + strcpy(str_ptr, dn_str);
> +
> + /* Add dn to list */
> + rtobj_list[rtobj_cnt] = str_ptr;
> + rtobj_cnt++;
> +
> + done:
> + TRACE_LEAVE2("rc = %d", rc);
> + return rc;
> +}
> +
> +/**
> + * Return number of names in list
> + *
> + * @return Number of names
> + */
> +int log_rtobj_list_no()
> +{
> + return rtobj_cnt;
> +}
> +
> +/**
> + * Find pos of the given given name in list
> + *
> + * @param dn_str[in] '\0' terminated string with dn to find
> + * @return Position of found name or -1 if name not found
> + */
> +int log_rtobj_list_find(char *dn_str)
> +{
> + uint32_t i = 0;
> + int pos = -1;
> +
> + TRACE_ENTER2("dn_str \"%s\"", dn_str);
> +
> + if (rtobj_list == NULL) {
> + TRACE("\t No rtobj_list exist");
> + goto done;
> + }
> +
> + for (i = 0; i < rtobj_list_len; i++) {
> + if (rtobj_list[i] == NULL)
> + continue;
> + if (strcmp(rtobj_list[i], dn_str) == 0) {
> + /* Found! */
> + pos = (int) i;
> + break;
> + }
> + }
> +
> +done:
> + TRACE_LEAVE2("pos = %d", pos);
> + return pos;
> +}
> +
> +/**
> + * Get pos of first name found in list.
> + *
> + * @return Position of found name or -1 if no name found
> + */
> +int log_rtobj_list_getnamepos()
> +{
> + uint32_t i = 0;
> + int pos = -1;
> +
> + for (i = 0; i < rtobj_list_len; i++) {
> + if (rtobj_list[i] == NULL) {
> + continue;
> + } else {
> + pos = static_cast<int>(i);
> + break;
> + }
> + }
> +
> + return pos;
> +}
> +
> +/**
> + * Get name at given pos in list.
> + *
> + * @param pos[in] Position for name to get
> + * @return A pointer to the string in given pos.
> + * If there is no string in pos or pos is outside the list
> + * NULL is returned.
> + */
> +char *log_rtobj_list_getname(int pos)
> +{
> + if (pos >= static_cast<int>(rtobj_list_len))
> + return NULL;
> +
> + return rtobj_list[pos];
> +}
> +
> +/**
> + * "Erase" dn name at pos in list
> + *
> + * @param pos[in] Position in list to erase
> + */
> +void log_rtobj_list_erase_one_pos(int pos)
> +{
> + TRACE_ENTER2("pos = %d", pos);
> + if (pos > static_cast<int>(rtobj_list_len)) {
> + TRACE_LEAVE2("%s\tPosition %d outside list!", __FUNCTION__,
> pos);
> + return;
> + }
> +
> + if (rtobj_list[pos] == NULL) {
> + TRACE_LEAVE2("%s\tNo string in pos %d", __FUNCTION__, pos);
> + return;
> + }
> +
> + free(rtobj_list[pos]);
> + rtobj_list[pos] = NULL;
> +
> + if (rtobj_cnt > 0)
> + rtobj_cnt--;
> +
> + TRACE_LEAVE();
> +}
> +
> +/***
> + * Restore a lost runtime stream.
> + * Get attributes from given runtime object (if exists).
> + * Find the last open logfile. From the file get number of log
> records written
> + * and latest used log record id
> + * If fail delete the stream IMM object (if exist)
> + * Always delete the object name from the rtobj list
> + */
> +
> +/**
> + * Local help function
> + * Find the file that was current log file before server down.
> + * Get file size
> + * Get last written record Id by reading the first characters of the
> last
> + * log record in the file
> + *
> + * NOTE:
> + * All file handling must be done in the file thread
> + * See lgs_get_file_params_hdl() in lgs_filehdl.c
> + *
> + * @param fileName[in] The name in saLogStreamFileName e.g. "app1"
> + * @param pathName[in] Full path to the dir where the log file can
> be found
> + * root path + relative path
> + * @param logFileCurrent[out]
> + * @param curFileSize[out]
> + * @param logRecordId[out]
> + *
> + * @return -1 on error
> + */
> +//static int lgs_get_file_params_h(gfp_in_t *par_in, gfp_out_t
> *par_out)
> +static int lgs_get_file_params_h(gfp_in_t *par_in, gfp_out_t
> *par_out)
> +{
> + lgsf_retcode_t api_rc;
> + lgsf_apipar_t apipar;
> + int rc = 0;
> +
> + TRACE_ENTER();
> +
> + /* Fill in API structure */
> + apipar.req_code_in = LGSF_GET_FILE_PAR;
> + apipar.data_in_size = sizeof(gfp_in_t);
> + apipar.data_in = par_in;
> + apipar.data_out_size = sizeof(gfp_out_t);
> + apipar.data_out = par_out;
> +
> + api_rc = log_file_api(&apipar);
> + if (api_rc != LGSF_SUCESS) {
> + TRACE("%s - API error %s", __FUNCTION__,
> + lgsf_retcode_str(api_rc));
> + rc = -1;
> + } else {
> + rc = apipar.hdl_ret_code_out;
> + TRACE("\t hdl_ret_code_out = %d", rc);
> + }
> +
> + TRACE_LEAVE();
> + return rc;
> +}
> +
> +static void lgs_remove_stream(uint32_t client_id, log_stream_t
> *log_stream)
> +{
> + TRACE_ENTER();
> +
> + /* Remove the stream handle and
> + * remove the stream resources
> + */
> + if (lgs_client_stream_rmv(client_id, log_stream->streamId) <
> 0) {
> + TRACE("%s lgs_client_stream_rmv Fail", __FUNCTION__);
> + }
> +
> + log_free_stream_resources(log_stream);
> +
> + log_stream = NULL;
> +
> + TRACE_LEAVE();
> +}
> +
> +/**
> + * Restore parameters for a lost runtime (application) stream, create
> the
> + * stream in the local stream list and associate with a client.
> + * Remove the stream object name from the found objects list.
> + *
> + * @param stream_name[in] The name of the stream
> + * @param client_id[in] Client to recover stream for
> + * @param o_stream[out] The recovered stream
> + * stream
> + * @return -1 on error
> + */
> +int lgs_restore_one_app_stream(
> + char *stream_name, uint32_t client_id,
> + log_stream_t **o_stream)
> +{
> + int int_rc = 0;
> + int rc_out = 0;
> + SaAisErrorT ais_rc = SA_AIS_OK;
> + SaImmHandleT immOmHandle;
> + SaImmAttrValuesT_2 *attribute;
> + SaImmAttrValuesT_2 **attributes;
> + gfp_in_t par_in;
> + gfp_out_t par_out;
> + int list_pos;
> + int n;
> + int i = 0;
> +
> + lgsv_stream_open_req_t open_stream_param;
> + log_stream_t *log_stream = NULL;
> + SaTimeT restored_creationTimeStamp = 0;
> + SaUint32T restored_severityFilter = 0;
> +
> + std::string fileName;
> + std::string pathName;
> +
> + // Make it safe for free
> + par_out.curFileName = NULL;
> +
> + TRACE_ENTER2("object_name \"%s\", client_id=%d", stream_name,
> client_id);
> +
> + memset(&open_stream_param, 0, sizeof(open_stream_param));
> +
> + /* Check and save stream file name */
> + if (stream_name == NULL) {
> + TRACE("%s: No object name <NULL>", __FUNCTION__);
> + rc_out = -1;
> + goto done;
> + }
> + n = snprintf(reinterpret_cast<char
> *>(open_stream_param.lstr_name.value),
> + SA_MAX_NAME_LENGTH, "%s", stream_name);
> +
> + open_stream_param.lstr_name.length = strlen(stream_name) + 1;
> + if (n >= SA_MAX_NAME_LENGTH) {
> + TRACE("Log stream name \"%s\" is truncated",
> + open_stream_param.lstr_name.value);
> + rc_out = -1;
> + goto done;
> + }
> +
> + /* Check if in found objects list */
> + list_pos = log_rtobj_list_find(stream_name);
> + if (list_pos == -1) {
> + TRACE("%s: No stream \"%s\" found to restore", __FUNCTION__,
> stream_name);
> + rc_out = -1;
> + goto done;
> + }
> +
> + /* Remove from list */
> + log_rtobj_list_erase_one_pos(list_pos);
> +
> + /* Get the cached attributes for the object
> + */
> + int_rc = lgs_get_streamobj_attr(&attributes, stream_name,
> &immOmHandle);
> + if (int_rc == -1) {
> + TRACE("%s:\t lgs_get_streamobj_attr Fail", __FUNCTION__);
> + rc_out = -1;
> + goto done;
> + }
> +
> + /* Fill in the "lgsv_stream_open_req_t open_stream_param" struct
> with
> + * recovered parameters, re-create the stream and add it to the
> client
> + * Note: Before restoring a stream the client to own the stream
> must
> + * exist.
> + */
> + i = 0;
> + while ((attribute = attributes[i++]) != NULL) {
> + void *value;
> + char *name;
> + char *str_val;
> +
> + /* Fill in parameters read from the app stream object
> + */
> + name = attribute->attrName;
> + if (attribute->attrValuesNumber != 0)
> + value = attribute->attrValues[0];
> + else {
> + value = NULL;
> + }
> +
> + TRACE("\t attribute name \"%s\"", name);
> + if (!strcmp(name, "saLogStreamFileName")) {
> + if (value == NULL) {
> + TRACE("%s: Fail, has empty value", name);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> +
> + fileName = *(static_cast<char **>(value));
> + TRACE("\t saLogStreamFileName \"%s\"",
> fileName.c_str());
> + } else if (!strcmp(name, "saLogStreamPathName")) {
> + if (value == NULL) {
> + TRACE("%s: Fail, has empty value", name);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> +
> + pathName = *(static_cast<char **>(value));
> + TRACE("\t saLogStreamPathName \"%s\"",
> pathName.c_str());
> + } else if (!strcmp(name, "saLogStreamMaxLogFileSize")) {
> + if (value == NULL) {
> + TRACE("%s: Fail, has empty value", name);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> +
> + open_stream_param.maxLogFileSize =
> *(static_cast<SaUint64T
> *>(value));
> + TRACE("\t saLogStreamMaxLogFileSize = %lld",
> + open_stream_param.maxLogFileSize);
> +
> + } else if (!strcmp(name, "saLogStreamFixedLogRecordSize")) {
> + if (value == NULL) {
> + TRACE("%s: Fail, has empty value", name);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> + open_stream_param.maxLogRecordSize =
> *(static_cast<SaUint32T
> *>(value));
> + TRACE("\t saLogStreamFixedLogRecordSize = %d",
> + open_stream_param.maxLogRecordSize);
> +
> + } else if (!strcmp(name, "saLogStreamHaProperty")) {
> + if (value == NULL) {
> + TRACE("%s: Fail, has empty value", name);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> + open_stream_param.haProperty = *(static_cast<SaBoolT
> *>(value));
> + TRACE("\t saLogStreamHaProperty=%d",
> + open_stream_param.haProperty);
> +
> + } else if (!strcmp(name, "saLogStreamLogFullAction")) {
> + if (value == NULL) {
> + TRACE("%s: Fail, has empty value", name);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> + open_stream_param.logFileFullAction =
> *(static_cast<SaLogFileFullActionT *>(value));
> + TRACE("\t saLogStreamLogFullAction=%d",
> + open_stream_param.logFileFullAction);
> +
> + } else if (!strcmp(name, "saLogStreamMaxFilesRotated")) {
> + if (value == NULL) {
> + TRACE("%s: Fail, has empty value", name);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> + open_stream_param.maxFilesRotated =
> *(static_cast<SaUint16T
> *>(value));
> + TRACE("\t saLogStreamMaxFilesRotated=%d",
> + open_stream_param.maxFilesRotated);
> +
> + } else if (!strcmp(name, "saLogStreamLogFileFormat")) {
> + /*TBD Is this correct way of handling format?
> + * - Must be checked!
> + * - Use better max length than PATH_MAX!
> + */
> + if (value == NULL) {
> + TRACE("%s: Fail, has empty value", name);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> + str_val = *(static_cast<char **>(value));
> + open_stream_param.logFileFmt = NULL;
> + open_stream_param.logFileFmt = static_cast<char *>(
> + calloc(1, strlen(str_val) + 1));
> + if (open_stream_param.logFileFmt == NULL) {
> + TRACE("%s [%d] calloc Fail",
> + __FUNCTION__, __LINE__);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> + n = snprintf(open_stream_param.logFileFmt,
> + PATH_MAX, "%s", str_val);
> + open_stream_param.logFileFmtLength =
> + strlen(open_stream_param.logFileFmt);
> + if (n >= PATH_MAX) {
> + TRACE("Format string \"%s\" too long",
> + str_val);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> + TRACE("\t saLogStreamLogFileFormat \"%s\"",
> + open_stream_param.logFileFmt);
> +
> + } else if (!strcmp(name, "saLogStreamCreationTimestamp")) {
> + if (value == NULL) {
> + TRACE("%s: Fail, has empty value", name);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> + restored_creationTimeStamp = *(static_cast<SaTimeT
> *>(value));
> + TRACE("\t saLogStreamCreationTimestamp=%lld",
> + restored_creationTimeStamp);
> +
> + } else if (!strcmp(name, "saLogStreamSeverityFilter")) {
> + if (value == NULL) {
> + TRACE("%s: Fail, has empty value", name);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> + restored_severityFilter = *(static_cast<SaUint32T
> *>(value));
> + TRACE("\t saLogStreamSeverityFilter=%d",
> + restored_severityFilter);
> + }
> + }
> +
> + /* Fill in the rest of the stream open parameters
> + * and create the stream. Do not create an IMM object
> + */
> + open_stream_param.client_id = client_id;
> + open_stream_param.lstr_open_flags = 0; /* Dummy not used here */
> +
> + open_stream_param.logFileName = const_cast<char
> *>(fileName.c_str());
> + open_stream_param.logFilePathName = const_cast<char
> *>(pathName.c_str());
> +
> + ais_rc = create_new_app_stream(&open_stream_param, &log_stream, 0);
> + if ( ais_rc != SA_AIS_OK) {
> + TRACE("%s: create_new_app_stream Fail %s",
> + __FUNCTION__, saf_error(ais_rc));
> + rc_out = -1;
> + goto done_free_attr;
> + }
> +
> + /* Create an association between this client and the stream */
> + int_rc = lgs_client_stream_add(client_id, log_stream->streamId);
> + if (int_rc == -1) {
> + TRACE("%s: lgs_client_stream_add Fail", __FUNCTION__);
> + log_free_stream_resources(log_stream); /* Undo create new stream
> */
> + rc_out = -1;
> + goto done_free_attr;
> + }
> +
> + /* Set values for attributes not restored when creating a stream.
> + * The value must be set after the stream is created.
> + * Cached:
> + * - saLogStreamSeverityFilter (cached)
> + * - saLogStreamCreationTimestamp (cached)
> + *
> + * Pure runtime:
> + * - saLogStreamNumOpeners
> + * Handled when streams are opened. No recovery needed
> + * - logStreamDiscardedCounter
> + * Cannot be restored. Initialized with 0
> + */
> + log_stream->creationTimeStamp = restored_creationTimeStamp;
> + log_stream->severityFilter = restored_severityFilter;
> + log_stream->filtered = 0;
> +
> + TRACE("\t Stream obj attributes handled and stream is created");
> +
> + /* Get recovery data from the log file and update the stream
> + */
> + pathName = static_cast<const char *>(
> + lgs_cfg_get(LGS_IMM_LOG_ROOT_DIRECTORY));
> + pathName = pathName + "/" + open_stream_param.logFilePathName;
> +
> + par_in.file_name = open_stream_param.logFileName;
> + par_in.file_path = const_cast<char *>(pathName.c_str());
> +
> + int_rc = lgs_get_file_params_h(&par_in, &par_out);
> + if (int_rc == -1) {
> + TRACE("%s:\t lgs_get_file_params_h Fail", __FUNCTION__);
> + /* Remove the stream handle and
> + * remove the stream resources
> + */
> + lgs_remove_stream(client_id, log_stream);
> + rc_out = -1;
> + goto done_free_attr;
> + }
> +
> + /* If no current log file create a file name
> + */
> + if (par_out.curFileName == NULL) {
> + /* There is no current log file. Create a file name */
> + log_stream->logFileCurrent = log_stream->fileName + "_" +
> lgs_get_time(NULL);
> + TRACE("\t A new file name for current log file is created");
> + } else {
> + log_stream->logFileCurrent = par_out.curFileName;
> + }
> +
> + TRACE("\t Current log file \"%s\"",
> log_stream->logFileCurrent.c_str());
> +
> + log_stream->curFileSize = par_out.curFileSize;
> + log_stream->logRecordId = par_out.logRecordId;
> +
> + /* The stream is open again and opened for the first time so far */
> + log_stream->numOpeners = 1;
> +
> + /* Set the stream file descriptor to -1. The file will then be
> opened
> + * at next write.
> + */
> + *log_stream->p_fd = -1;
> +
> +done_free_attr:
> + /* Free resources used for finding attribute values */
> + int_rc = lgs_free_streamobj_attr(immOmHandle);
> + if (int_rc == -1) {
> + TRACE("%s:\t lgs_free_streamobj_attr Fail", __FUNCTION__);
> + rc_out = -1;
> + }
> +
> +done:
> + free(open_stream_param.logFileFmt);
> + if (par_out.curFileName != NULL) {
> + // This memory is allocated in lgs_get_file_params_hdl()
> + free(par_out.curFileName);
> + }
> +
> + /* Return recovered stream. Will be NULL if not recovered (rc_out =
> -1) */
> + *o_stream = log_stream;
> + TRACE_LEAVE2("rc_out = %d", rc_out);
> + return rc_out;
> +}
> +
> +/**
> + * Restore lost files for a configuration stream.
> + * Update the stream with current log file and log record Id
> + *
> + *
> + * @param log_stream[in/out]
> + * Will/May modify the following stream parameters:
> + * logFileCurrent
> + * curFileSize
> + * logRecordId
> + * creationTimeStamp
> + * *p_fd
> + * numOpeners
> + *
> + * @return -1 on error
> + */
> +int log_stream_open_file_restore(log_stream_t *stream)
> +{
> + int int_rc = 0;
> + int rc_out = 0;
> + gfp_in_t par_in;
> + gfp_out_t par_out;
> + std::string pathName, log_root_path;
> + size_t name_length = lgs_max_nlength();
> +
> + TRACE_ENTER();
> +
> + pathName = static_cast<const char
> *>(lgs_cfg_get(LGS_IMM_LOG_ROOT_DIRECTORY));
> + pathName = pathName + "/" + stream->pathName;
> +
> + par_in.file_name = const_cast<char *>(stream->fileName.c_str());
> + par_in.file_path = const_cast<char *>(pathName.c_str());
> +
> + TRACE("pathName = %s, fileName = %s, name_length = %zu",
> + pathName.c_str(), stream->fileName.c_str(), name_length);
> +
> + // Initialize the output
> + par_out.curFileSize = 0;
> + par_out.logRecordId = 0;
> + par_out.curFileName = NULL;
> +
> + int_rc = lgs_get_file_params_h(&par_in, &par_out);
> +
> + /****
> + * Rules for lgs_get_file_params_h():
> + * - If current log file not empty: Name = cur log file, Size = file
> size,
> + * Id = fr file, rc = OK
> + * - If current log file empty no rotated: Name = cur log file, Size
> = 0,
> + * Id = 1, rc = OK
> + * - If current log file empty is rotated: Name = cur log file, Size
> = 0,
> + * Id = fr last rotated, rc
> = OK
> + * - If no log file at all: Name = NULL, Size = 0, Id = 1, rc = OK
> + * - If only rotated log file: Name = NULL, Size = 0, Id = fr
> rotated file,
> + * rc = OK
> + */
> +
> + if (int_rc == -1) {
> + /* No relevant file info found. Recovery fail */
> + TRACE("%s: lgs_get_file_params_h Fail", __FUNCTION__);
> + rc_out = -1;
> + goto done;
> + }
> +
> + stream->logFileCurrent = par_out.curFileName;
> + stream->curFileSize = par_out.curFileSize;
> + stream->logRecordId = par_out.logRecordId;
> +
> + TRACE("Out: curFileSize = %u, logRecordId = %u, logFileCurrent =
> %s",
> + stream->curFileSize, stream->logRecordId,
> stream->logFileCurrent.c_str());
> +
> + if (stream->numOpeners != 0) {
> + TRACE("%s: numOpeners = %u Fail", __FUNCTION__,
> stream->numOpeners);
> + rc_out = -1;
> + goto done;
> + }
> +
> + int errno_save;
> + log_root_path = static_cast<const char
> *>(lgs_cfg_get(LGS_IMM_LOG_ROOT_DIRECTORY));
> + *stream->p_fd = -1;
> +
> + if ((*stream->p_fd = log_file_open(log_root_path, stream,
> + stream->logFileCurrent,
> + &errno_save)) == -1) {
> + TRACE("%s - Could not open '%s' - %s", __FUNCTION__,
> + stream->logFileCurrent.c_str(), strerror(errno_save));
> + }
> +
> + stream->numOpeners++;
> +
> +done:
> + // This memory is allocated in lgs_get_file_params_hdl()
> + if (par_out.curFileName != NULL)
> + free(par_out.curFileName);
> +
> + TRACE_LEAVE2("rc_out = %d", rc_out);
> + return rc_out;
> +}
> diff --git a/osaf/services/saf/logsv/lgs/lgs_recov.h
> b/osaf/services/saf/logsv/lgs/lgs_recov.h
> new file mode 100644
> --- /dev/null
> +++ b/osaf/services/saf/logsv/lgs/lgs_recov.h
> @@ -0,0 +1,37 @@
> +/* -*- OpenSAF -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful,
> but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are
> licensed
> + * under the GNU Lesser General Public License Version 2.1, February
> 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for
> full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#ifndef LGS_STATE_H
> +#define LGS_STATE_H
> +
> +#include "lgs.h"
> +
> +int log_rtobj_list_add(char *dn_str);
> +int log_rtobj_list_no();
> +int log_rtobj_list_find(char *stream_name);
> +int log_rtobj_list_getnamepos();
> +char *log_rtobj_list_getname(int pos);
> +void log_rtobj_list_erase_one_pos(int pos);
> +void log_rtobj_list_free();
> +int lgs_restore_one_app_stream(
> + char *stream_name,
> + uint32_t client_id,
> + log_stream_t **o_stream
> + );
> +int log_stream_open_file_restore(log_stream_t *log_stream);
> +
> +#endif /* LGS_STATE_H */
> diff --git a/osaf/services/saf/logsv/lgs/lgs_stream.cc
> b/osaf/services/saf/logsv/lgs/lgs_stream.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_stream.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_stream.cc
> @@ -409,6 +409,33 @@ void log_stream_print(log_stream_t *stre
> TRACE_2(" filtered: %llu", stream->filtered);
> }
>
> +/**
> + * Free stream resources
> + *
> + * @param stream[in]
> + */
> +void log_free_stream_resources(log_stream_t *stream)
> +{
> + if (stream->streamId != 0)
> + lgs_stream_array_remove(stream->streamId);
> +
> + if (stream->pat_node.key_info != NULL)
> + log_stream_remove(stream->name);
> +
> + if (stream->logFileFormat != NULL)
> + free(stream->logFileFormat);
> +
> + delete stream;
> + stream = NULL;
> +}
> +
> +/**
> + * Remove a log stream including:
> + * - Runtime object if application stream and active
> + * - Remove stream resources (allocated memory)
> + *
> + * @param s[in] Pointer to the array of streams
> + */
> void log_stream_delete(log_stream_t **s)
> {
> log_stream_t *stream;
> @@ -469,6 +496,12 @@ static void init_log_stream_fd(log_strea
> * Create a new stream object. If HA state active, create the
> * correspronding IMM runtime object.
> *
> + * Note: log_stream_new() is replaced by this function.
> + * The new function is doing the same as the old but the
> possibility
> + * to create a stream without creating a corresponding runtime
> object
> + * is added. See creationFlag parameter
> + *
> + * Stream attributes[in]:
> * @param name
> * @param filename
> * @param pathname
> @@ -484,17 +517,21 @@ static void init_log_stream_fd(log_strea
> *
> * @return log_stream_t*
> */
> -log_stream_t *log_stream_new(SaNameT *dn,
> - const std::string &filename,
> - const std::string &pathname,
> - SaUint64T maxLogFileSize,
> - SaUint32T fixedLogRecordSize,
> - SaLogFileFullActionT logFullAction,
> - SaUint32T maxFilesRotated,
> - const char *logFileFormat,
> - logStreamTypeT streamType, int stream_id,
> - SaBoolT twelveHourModeFlag,
> - uint32_t logRecordId)
> +log_stream_t *log_stream_new_1(
> + SaNameT *dn,
> + const std::string &filename,
> + const std::string &pathname,
> + SaUint64T maxLogFileSize,
> + SaUint32T fixedLogRecordSize,
> + SaLogFileFullActionT logFullAction,
> + SaUint32T maxFilesRotated,
> + const char *logFileFormat,
> + logStreamTypeT streamType,
> + int stream_id,
> + SaBoolT twelveHourModeFlag,
> + uint32_t logRecordId,
> + int creationFlag
> + )
> {
> int rc;
> log_stream_t *stream = NULL;
> @@ -690,10 +727,10 @@ log_stream_t *log_stream_new(SaNameT *dn
> }
>
> /**
> - * Create a new stream object. Do not create an IMM runtime object.
> + * Create a new default stream. Do not create an IMM runtime object.
> * @param name
> * @param stream_id
> - *
> + *
> * @return log_stream_t*
> */
> log_stream_t *log_stream_new_2(SaNameT *name, int stream_id)
> @@ -704,7 +741,7 @@ log_stream_t *log_stream_new_2(SaNameT *
> osafassert(name != NULL);
> TRACE_ENTER2("%s, l: %u", name->value, (unsigned int)name->length);
>
> - stream = new (std::nothrow) (log_stream_t)();
> + stream = new (std::nothrow) log_stream_t();
> if (stream == NULL) {
> LOG_WA("calloc FAILED");
> goto done;
> diff --git a/osaf/services/saf/logsv/lgs/lgs_stream.h
> b/osaf/services/saf/logsv/lgs/lgs_stream.h
> --- a/osaf/services/saf/logsv/lgs/lgs_stream.h
> +++ b/osaf/services/saf/logsv/lgs/lgs_stream.h
> @@ -79,18 +79,21 @@ extern uint32_t log_stream_init();
> extern void log_stream_delete(log_stream_t **s);
>
> #define STREAM_NEW -1
> -extern log_stream_t *log_stream_new(SaNameT *name,
> - const std::string &filename,
> - const std::string &pathname,
> - SaUint64T maxLogFileSize,
> - SaUint32T fixedLogRecordSize,
> - SaLogFileFullActionT logFullAction,
> - SaUint32T maxFilesRotated,
> - const char *logFileFormat,
> - logStreamTypeT streamType,
> - int stream_id,
> - SaBoolT twelveHourModeFlag,
> - uint32_t logRecordId);
> +extern log_stream_t *log_stream_new_1(
> + SaNameT *name,
> + const std::string &filename,
> + const std::string &pathname,
> + SaUint64T maxLogFileSize,
> + SaUint32T fixedLogRecordSize,
> + SaLogFileFullActionT logFullAction,
> + SaUint32T maxFilesRotated,
> + const char *logFileFormat,
> + logStreamTypeT streamType,
> + int stream_id,
> + SaBoolT twelveHourModeFlag,
> + uint32_t logRecordId,
> + int creationFlag
> + );
>
> extern log_stream_t *log_stream_new_2(SaNameT *name, int stream_id);
>
> @@ -118,5 +121,6 @@ extern log_stream_t *log_stream_get_by_n
> extern log_stream_t *log_stream_getnext_by_name(const char *name);
> extern void log_stream_print(log_stream_t *stream);
> extern log_stream_t *log_stream_get_by_id(uint32_t id);
> +void log_free_stream_resources(log_stream_t *stream);
>
> #endif
> diff --git a/osaf/services/saf/logsv/lgs/lgs_util.cc
> b/osaf/services/saf/logsv/lgs/lgs_util.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_util.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_util.cc
> @@ -30,12 +30,13 @@
>
> #include <stdlib.h>
> #include <grp.h>
> +#include <osaf_time.h>
>
> #include "immutil.h"
> #include "lgs.h"
> #include "lgs_file.h"
> #include "lgs_filehdl.h"
> -#include "osaf_time.h"
> +#include "osaf_timerfd.h"
>
> #define ALARM_STREAM_ENV_PREFIX "ALARM"
> #define NOTIFICATION_STREAM_ENV_PREFIX "NOTIFICATION"
> @@ -239,14 +240,14 @@ SaTimeT lgs_get_SaTime()
> * @param root_path[in]
> * @param rel_path[in]
> * @param old_name[in]
> - * @param time_stamp[in]
> + * @param time_stamp[in]
> * Can be set to NULL but then new_name must be the complete
> new name
> * including time stamps but without suffix
> * @param suffix[in]
> - * @param new_name[in/out]
> - * Pointer to char string of NAME_MAX size
> + * @param new_name[in/out]
> + * Pointer to char string
> * Filename of renamed file. Can be set to NULL
> - *
> + *
> * @return -1 if error
> */
> int lgs_file_rename_h(
> @@ -638,6 +639,45 @@ done:
> }
>
> /**
> + * Initiate a timer:
> + * Creates a timeout timer, set timeout time and starts the timer
> + * returns a file descriptor to the timer that can be used with
> poll()
> + * See also osaf_timerfd.h
> + *
> + * @param timeout_s[in] Timeout time in seconds
> + * @return fd File descriptor referring to the created timer
> + */
> +int lgs_init_timer(time_t timeout_s)
> +{
> + int fd;
> + struct itimerspec lgs_cltimer;
> +
> + fd = osaf_timerfd_create(CLOCK_MONOTONIC, 0);
> +
> + /* Set timeout time. Do not use as interval timer */
> + lgs_cltimer.it_interval.tv_sec = 0;
> + lgs_cltimer.it_interval.tv_nsec = 0;
> + /* Set timeout in seconds */
> + lgs_cltimer.it_value.tv_sec = timeout_s;
> + lgs_cltimer.it_value.tv_nsec = 0;
> +
> + osaf_timerfd_settime(fd, 0, &lgs_cltimer, NULL);
> +
> + return fd;
> +}
> +
> +/**
> + * Close a timer created with lgs_init_timer()
> + * See also osaf_timerfd.h
> + *
> + * @param ufd[in]
> + */
> +void lgs_close_timer(int ufd)
> +{
> + osaf_timerfd_close(ufd);
> +}
> +
> +/**
> * Validate if string contains special characters or not
> *
> * @param: str [in] input string for checking
> diff --git a/osaf/services/saf/logsv/lgs/lgs_util.h
> b/osaf/services/saf/logsv/lgs/lgs_util.h
> --- a/osaf/services/saf/logsv/lgs/lgs_util.h
> +++ b/osaf/services/saf/logsv/lgs/lgs_util.h
> @@ -77,4 +77,8 @@ bool lgs_is_valid_pathlength(const std::
> const std::string &fileName,
> const std::string &rootPath = "");
>
> +/* Timer functions */
> +int lgs_init_timer(time_t timeout_s);
> +void lgs_close_timer(int ufd);
> +
> #endif /* ifndef __LGS_UTIL_H */
------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140
_______________________________________________
Opensaf-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensaf-devel