Thanks, Mathi. Here is the fix for comments of patch 1/4 and 2/4.
Regards, Vu. >-----Original Message----- >From: Mathivanan Naickan Palanivelu [mailto:[email protected]] >Sent: Wednesday, February 24, 2016 5:24 PM >To: [email protected] >Cc: [email protected]; [email protected]; >[email protected] >Subject: Re: [PATCH 1 of 4] log: add support for cloud resilience feature >(service >part) [#1179] > >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 */
lgsv_cloud_fix_rvcomment_p2.patch
Description: Binary data
------------------------------------------------------------------------------ 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
