Sorry. Please take this attach. Regards, Vu.
>-----Original Message----- >From: Vu Minh Nguyen [mailto:[email protected]] >Sent: Thursday, February 25, 2016 9:23 AM >To: 'Mathivanan Naickan Palanivelu'; [email protected] >Cc: [email protected] >Subject: Re: [devel] [PATCH 1 of 4] log: add support for cloud resilience >feature >(service part) [#1179] > >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
