Ack for patch 1, You could use %PRIx64 for MDS addresses. Mathi. ----- vu.m.ngu...@dektech.com.au 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 Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel