Hi Lennart,

I see you make `oiCreationThread_`  as a joinable thread, it means
`joinable()` always returns true until the thread has been joined (when
switch-over).

So, if LOGsv gets SA_AIS_BAD_HANDLE returned by IMM APIs second time, the
recovery job will not be activated due to below condition.

if ((oiCreationThread_.joinable() == true) || (stop_oi_create == true)) {
    // Thread is executing. Do nothing
    return;
  }

That is not what we expect, I think.

Regards, Vu

> -----Original Message-----
> From: Lennart Lund [mailto:lennart.l...@ericsson.com]
> Sent: Wednesday, March 28, 2018 9:34 PM
> To: vu.m.ngu...@dektech.com.au; canh.v.tru...@dektech.com.au
> Cc: opensaf-devel@lists.sourceforge.net; Lennart Lund
> <lennart.l...@ericsson.com>
> Subject: [PATCH 1/1] log: Handling of IMM OI BAD HANDLE in log server is
> incorrect [#2799]
> 
> Recovery of OI handle shall be started in all places where BAD HANDLE
> can be returned. Creation of OI must be done in background thread.
> Ongoing creation must be possible to stop e.g if server is becoming
> standby
> ---
>  src/log/Makefile.am          |   3 +
>  src/log/logd/lgs.h           |  24 ---
>  src/log/logd/lgs_amf.cc      |  26 ++-
>  src/log/logd/lgs_cb.h        |   3 -
>  src/log/logd/lgs_config.cc   |  22 ++-
>  src/log/logd/lgs_config.h    |   5 +-
>  src/log/logd/lgs_evt.cc      |  60 +++---
>  src/log/logd/lgs_imm.cc      | 312 +++--------------------------
>  src/log/logd/lgs_imm.h       |  53 +++++
>  src/log/logd/lgs_main.cc     | 116 ++++-------
>  src/log/logd/lgs_mbcsv_v2.cc |   7 +-
>  src/log/logd/lgs_mbcsv_v3.cc |   7 +-
>  src/log/logd/lgs_mbcsv_v5.cc |   3 +-
>  src/log/logd/lgs_oi_admin.cc | 461
> +++++++++++++++++++++++++++++++++++++++++++
>  src/log/logd/lgs_oi_admin.h  | 105 ++++++++++
>  src/log/logd/lgs_recov.cc    |   4 +-
>  src/log/logd/lgs_stream.cc   |  85 ++++++--
>  17 files changed, 837 insertions(+), 459 deletions(-)
>  create mode 100644 src/log/logd/lgs_imm.h
>  create mode 100644 src/log/logd/lgs_oi_admin.cc
>  create mode 100644 src/log/logd/lgs_oi_admin.h
> 
> diff --git a/src/log/Makefile.am b/src/log/Makefile.am
> index 3d951eb5d..5d33d355b 100644
> --- a/src/log/Makefile.am
> +++ b/src/log/Makefile.am
> @@ -79,6 +79,7 @@ noinst_HEADERS += \
>       src/log/logd/lgs_file.h \
>       src/log/logd/lgs_filehdl.h \
>       src/log/logd/lgs_fmt.h \
> +     src/log/logd/lgs_imm.h \
>       src/log/logd/lgs_imm_gcfg.h \
>       src/log/logd/lgs_mbcsv.h \
>       src/log/logd/lgs_mbcsv_v1.h \
> @@ -86,6 +87,7 @@ noinst_HEADERS += \
>       src/log/logd/lgs_mbcsv_v3.h \
>       src/log/logd/lgs_mbcsv_v5.h \
>       src/log/logd/lgs_mbcsv_v6.h \
> +     src/log/logd/lgs_oi_admin.h \
>       src/log/logd/lgs_recov.h \
>       src/log/logd/lgs_stream.h \
>       src/log/logd/lgs_util.h \
> @@ -139,6 +141,7 @@ bin_osaflogd_SOURCES = \
>       src/log/logd/lgs_mbcsv_v5.cc \
>       src/log/logd/lgs_mbcsv_v6.cc \
>       src/log/logd/lgs_mds.cc \
> +     src/log/logd/lgs_oi_admin.cc \
>       src/log/logd/lgs_recov.cc \
>       src/log/logd/lgs_stream.cc \
>       src/log/logd/lgs_util.cc \
> diff --git a/src/log/logd/lgs.h b/src/log/logd/lgs.h
> index 18e6d9281..b1d773375 100644
> --- a/src/log/logd/lgs.h
> +++ b/src/log/logd/lgs.h
> @@ -95,7 +95,6 @@ extern uint32_t mbox_msgs[NCS_IPC_PRIORITY_MAX];
>  extern bool mbox_full[NCS_IPC_PRIORITY_MAX];
>  extern uint32_t mbox_low[NCS_IPC_PRIORITY_MAX];
>  extern pthread_mutex_t lgs_mbox_init_mutex;
> -extern pthread_mutex_t lgs_OI_init_mutex;
> 
>  extern uint32_t initialize_for_assignment(lgs_cb_t *cb, SaAmfHAStateT
> ha_state);
> 
> @@ -108,27 +107,4 @@ extern uint32_t lgs_mds_msg_send(lgs_cb_t *cb,
> lgsv_msg_t *msg, MDS_DEST *dest,
>                                   MDS_SYNC_SND_CTXT *mds_ctxt,
>                                   MDS_SEND_PRIORITY_TYPE prio);
> 
> -extern SaAisErrorT lgs_imm_create_configStream(lgs_cb_t *cb);
> -extern void logRootDirectory_filemove(const std::string
> &new_logRootDirectory,
> -                                      const std::string
&old_logRootDirectory,
> -                                      time_t *cur_time_in);
> -extern void logDataGroupname_fileown(const char
> *new_logDataGroupname);
> -
> -extern void lgs_imm_impl_reinit_nonblocking(lgs_cb_t *cb);
> -extern void lgs_imm_init_OI_handle(SaImmOiHandleT *immOiHandle,
> -                                   SaSelectionObjectT
*immSelectionObject);
> -extern void lgs_imm_impl_set(SaImmOiHandleT *immOiHandle,
> -                             SaSelectionObjectT *immSelectionObject);
> -extern SaAisErrorT lgs_imm_init_configStreams(lgs_cb_t *cb);
> -
> -// Functions for recovery handling
> -void lgs_cleanup_abandoned_streams();
> -void lgs_delete_one_stream_object(const std::string &name_str);
> -void lgs_search_stream_objects();
> -SaUint32T *lgs_get_scAbsenceAllowed_attr(SaUint32T *attr_val);
> -int lgs_get_streamobj_attr(SaImmAttrValuesT_2 ***attrib_out,
> -                           const std::string &object_name,
> -                           SaImmHandleT *immOmHandle);
> -int lgs_free_streamobj_attr(SaImmHandleT immHandle);
> -
>  #endif  // LOG_LOGD_LGS_H_
> diff --git a/src/log/logd/lgs_amf.cc b/src/log/logd/lgs_amf.cc
> index 6fa044ff2..3f0de8c1c 100644
> --- a/src/log/logd/lgs_amf.cc
> +++ b/src/log/logd/lgs_amf.cc
> @@ -23,6 +23,7 @@
>  #include "osaf/immutil/immutil.h"
>  #include "log/logd/lgs.h"
>  #include "log/logd/lgs_config.h"
> +#include "log/logd/lgs_oi_admin.h"
> 
>  static void close_all_files() {
>    log_stream_t *stream;
> @@ -63,8 +64,7 @@ static SaAisErrorT amf_active_state_handler(lgs_cb_t
> *cb,
>      goto done;
>    }
> 
> -  lgs_imm_impl_set(&cb->immOiHandle, &cb->immSelectionObject);
> -  conf_runtime_obj_create(cb->immOiHandle);
> +  lgsOiStart();
>    lgs_start_gcfg_applier();
> 
>    // Iterate all existing log streams in cluster.
> @@ -127,12 +127,8 @@ static SaAisErrorT
> amf_quiescing_state_handler(lgs_cb_t *cb,
>    TRACE_ENTER2("HA QUIESCING request");
>    close_all_files();
> 
> -  /* Give up our IMM OI implementer role */
> -  SaAisErrorT ais_rc = immutil_saImmOiImplementerClear(cb-
> >immOiHandle);
> -  if (ais_rc != SA_AIS_OK) {
> -    LOG_WA("immutil_saImmOiImplementerClear failed: %s",
> saf_error(ais_rc));
> -  }
> -
> +  // Give up our IMM OI implementer role and the OpensafConfig class
> applier
> +  lgsOiStop();
>    lgs_stop_gcfg_applier();
> 
>    return saAmfCSIQuiescingComplete(cb->amf_hdl, invocation, SA_AIS_OK);
> @@ -158,11 +154,7 @@ static SaAisErrorT
> amf_quiesced_state_handler(lgs_cb_t *cb,
>    close_all_files();
> 
>    /* Give up our IMM OI implementer role */
> -  SaAisErrorT rc = immutil_saImmOiImplementerClear(cb->immOiHandle);
> -  if (rc != SA_AIS_OK) {
> -    LOG_WA("immutil_saImmOiImplementerClear failed: %s", saf_error(rc));
> -  }
> -
> +  lgsOiStop();
>    lgs_stop_gcfg_applier();
> 
>    /*
> @@ -171,11 +163,13 @@ static SaAisErrorT
> amf_quiesced_state_handler(lgs_cb_t *cb,
>    ** cb->ha_state now.
>    */
> 
> +
>    mds_role = cb->mds_role;
>    cb->mds_role = V_DEST_RL_QUIESCED;
> +  SaAisErrorT ais_rc = SA_AIS_OK;
>    if (lgs_mds_change_role(cb) != NCSCC_RC_SUCCESS) {
>      LOG_ER("lgs_mds_change_role FAILED");
> -    rc = SA_AIS_ERR_FAILED_OPERATION;
> +    ais_rc = SA_AIS_ERR_FAILED_OPERATION;
>      cb->mds_role = mds_role;
>      goto done;
>    }
> @@ -183,8 +177,9 @@ static SaAisErrorT
> amf_quiesced_state_handler(lgs_cb_t *cb,
>    cb->amf_invocation_id = invocation;
>    cb->is_quiesced_set = true;
>  done:
> -  return rc;
> +  return ais_rc;
>  }
> +
> 
> /**************************************************************
> **************
>   * Name          : amf_health_chk_callback
>   *
> @@ -207,6 +202,7 @@ static void amf_health_chk_callback(SaInvocationT
> invocation,
>                                      SaAmfHealthcheckKeyT *checkType) {
>    saAmfResponse(lgs_cb->amf_hdl, invocation, SA_AIS_OK);
>  }
> +
> 
> /**************************************************************
> **************
>   * Name          : amf_csi_set_callback
>   *
> diff --git a/src/log/logd/lgs_cb.h b/src/log/logd/lgs_cb.h
> index f2602c2d8..1b1a67d9c 100644
> --- a/src/log/logd/lgs_cb.h
> +++ b/src/log/logd/lgs_cb.h
> @@ -81,9 +81,6 @@ typedef struct lgs_cb {
>    SaInvocationT
>        amf_invocation_id; /* AMF InvocationID - needed to handle Quiesed
> state */
>    bool is_quiesced_set;
> -  SaImmOiHandleT immOiHandle; /* IMM OI handle
*/
> -  SaSelectionObjectT
> -      immSelectionObject; /* Selection Object to wait for IMM events */
>    SaSelectionObjectT
>        clmSelectionObject;  /* Selection Object to wait for clms events */
>    SaClmHandleT clm_hdl;    /* CLM handle, obtained through CLM init
*/
> diff --git a/src/log/logd/lgs_config.cc b/src/log/logd/lgs_config.cc
> index 4190e3048..7be92a6fa 100644
> --- a/src/log/logd/lgs_config.cc
> +++ b/src/log/logd/lgs_config.cc
> @@ -41,6 +41,7 @@
>  #include "log/logd/lgs_file.h"
>  #include "log/logd/lgs.h"
>  #include "log/logd/lgs_common.h"
> +#include "log/logd/lgs_oi_admin.h"
> 
> 
>  /* Mutex for making read and write of configuration data thread safe */
> @@ -1338,8 +1339,8 @@ static void read_log_config_environ_var_2() {
>   * Public functions for handling configuration information
> 
> **************************************************************
> ****************/
> 
> -void lgs_cfg_init(SaImmOiHandleT immOiHandle, SaAmfHAStateT ha_state) {
> -  TRACE_ENTER2("immOiHandle = %lld", immOiHandle);
> +void lgs_cfg_init() {
> +  TRACE_ENTER();
> 
>    /* Read configuration step 1
>     * Read all values from the log service configuration object
> @@ -1585,6 +1586,10 @@ void conf_runtime_obj_create(SaImmOiHandleT
> immOiHandle) {
> 
>    if (rc == SA_AIS_ERR_EXIST) {
>      TRACE("Server runtime configuration object already exist");
> +  } else if (rc == SA_AIS_ERR_BAD_HANDLE) {
> +    LOG_NO("%s: saImmOiRtObjectCreate_2 BAD_HANDLE, start re-create",
> +           __FUNCTION__);
> +    lgsOiCreateBackground();
>    } else if (rc != SA_AIS_OK) {
>      LOG_NO("%s: Cannot create config runtime object %s", __FUNCTION__,
>             saf_error(rc));
> @@ -1667,6 +1672,14 @@ static SaAisErrorT update_runtime_attrValues(
>    attrMod.modAttr.attrValueType = attrValueType;
>    attrMod.modAttr.attrValues = values_array;
>    ais_rc = immutil_saImmOiRtObjectUpdate_2(immOiHandle, &objectName,
> attrMods);
> +  if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
> +    LOG_NO("%s: saImmOiRtObjectUpdate_2() Fail, %s", __FUNCTION__,
> +           saf_error(ais_rc));
> +    lgsOiCreateBackground();
> +  } else if (ais_rc != SA_AIS_OK) {
> +    LOG_NO("%s: saImmOiRtObjectUpdate_2() Fail, %s", __FUNCTION__,
> +           saf_error(ais_rc));
> +  }
>    free(values_array);
>    TRACE_LEAVE();
>    return ais_rc;
> @@ -1692,8 +1705,7 @@ static SaAisErrorT
> update_lgs_cfg_runtime_multivalue(
>        immOiHandle, LGS_CFG_RUNTIME_OBJECT, attributeName, valueType,
>        attrValuesNumber, attrValues);
>    if (ais_rc != SA_AIS_OK) {
> -    LOG_NO("%s: update_runtime_attrValues Fail %s", __FUNCTION__,
> -           saf_error(ais_rc));
> +    LOG_NO("%s: update_runtime_attrValues Fail", __FUNCTION__);
>    }
> 
>    // Free the memory allocated by vector_of_strings_to_attrValues()
> @@ -1712,7 +1724,7 @@ static SaAisErrorT
> update_lgs_cfg_runtime_multivalue(
>   * @param immOiHandle[in]
>   * @param attributeNames[in]
>   */
> -void conf_runtime_obj_hdl(SaImmOiHandleT immOiHandle,
> +void conf_runtime_obj_handler(SaImmOiHandleT immOiHandle,
>                            const SaImmAttrNameT *attributeNames) {
>    SaImmAttrNameT attributeName;
>    int i = 0;
> diff --git a/src/log/logd/lgs_config.h b/src/log/logd/lgs_config.h
> index 6885271a4..3f1b05e51 100644
> --- a/src/log/logd/lgs_config.h
> +++ b/src/log/logd/lgs_config.h
> @@ -135,7 +135,7 @@ typedef struct config_chkpt {
>   * Read the log service configuration data verify and update
configuration
>   * data structure
>   */
> -void lgs_cfg_init(SaImmOiHandleT immOiHandle, SaAmfHAStateT ha_state);
> +void lgs_cfg_init();
> 
>  /**
>   * Get value of log service configuration parameter from the
configuration
> data
> @@ -316,8 +316,9 @@ void lgs_groupnameconf_set(const char
> *data_groupname_str);
>   * Handle runtime object for showing actual configuration and
configuration
>   * related information
>   */
> +
>  void conf_runtime_obj_create(SaImmOiHandleT immOiHandle);
> -void conf_runtime_obj_hdl(SaImmOiHandleT immOiHandle,
> +void conf_runtime_obj_handler(SaImmOiHandleT immOiHandle,
>                            const SaImmAttrNameT *attributeNames);
> 
>  /*
> diff --git a/src/log/logd/lgs_evt.cc b/src/log/logd/lgs_evt.cc
> index 4b735875d..d0c3161a4 100644
> --- a/src/log/logd/lgs_evt.cc
> +++ b/src/log/logd/lgs_evt.cc
> @@ -31,6 +31,7 @@
>  #include "log/logd/lgs_imm_gcfg.h"
>  #include "log/logd/lgs_clm.h"
>  #include "log/logd/lgs_dest.h"
> +#include "log/logd/lgs_oi_admin.h"
> 
>  void *client_db = nullptr; /* used for C++ STL map */
> 
> @@ -569,7 +570,7 @@ static uint32_t proc_rda_cb_msg(lgsv_lgs_evt_t
> *evt) {
>      }
> 
>      /* fail over, become implementer */
> -    lgs_imm_impl_set(&lgs_cb->immOiHandle, &lgs_cb-
> >immSelectionObject);
> +    lgsOiCreateBackground();
>      lgs_start_gcfg_applier();
> 
>      /* Agent down list has to be processed first */
> @@ -613,7 +614,6 @@ uint32_t lgs_cb_init(lgs_cb_t *lgs_cb) {
> 
>    lgs_cb->fully_initialized = false;
>    lgs_cb->amfSelectionObject = -1;
> -  lgs_cb->immSelectionObject = -1;
>    lgs_cb->mbcsv_sel_obj = -1;
>    lgs_cb->clm_hdl = 0;
>    lgs_cb->clmSelectionObject = -1;
> @@ -835,7 +835,7 @@ snd_rsp:
>   */
>  SaAisErrorT create_new_app_stream(lgsv_stream_open_req_t
> *open_sync_param,
>                                    log_stream_t **o_stream) {
> -  SaAisErrorT rc = SA_AIS_OK;
> +  SaAisErrorT ais_rc = SA_AIS_OK;
>    log_stream_t *stream;
>    SaBoolT twelveHourModeFlag;
>    SaUint32T logMaxLogrecsize_conf = 0;
> @@ -848,13 +848,13 @@ SaAisErrorT
> create_new_app_stream(lgsv_stream_open_req_t *open_sync_param,
> 
>    if (lgs_is_extended_name_valid(&open_sync_param->lstr_name) == false) {
>      TRACE("SaNameT is invalid");
> -    rc = SA_AIS_ERR_INVALID_PARAM;
> +    ais_rc = SA_AIS_ERR_INVALID_PARAM;
>      goto done;
>    }
> 
>    if (open_sync_param->logFileFullAction !=
> SA_LOG_FILE_FULL_ACTION_ROTATE) {
>      TRACE("Unsupported logFileFullAction");
> -    rc = SA_AIS_ERR_NOT_SUPPORTED;
> +    ais_rc = SA_AIS_ERR_NOT_SUPPORTED;
>      goto done;
>    }
> 
> @@ -864,7 +864,7 @@ SaAisErrorT
> create_new_app_stream(lgsv_stream_open_req_t *open_sync_param,
>        ((open_sync_param->maxFilesRotated < 1) ||
>         (open_sync_param->maxFilesRotated > 127))) {
>      TRACE("Invalid maxFilesRotated. Valid Range = [1-127]");
> -    rc = SA_AIS_ERR_INVALID_PARAM;
> +    ais_rc = SA_AIS_ERR_INVALID_PARAM;
>      goto done;
>    }
> 
> @@ -880,21 +880,21 @@ SaAisErrorT
> create_new_app_stream(lgsv_stream_open_req_t *open_sync_param,
>                                        STREAM_TYPE_APPLICATION_RT,
>                                        &twelveHourModeFlag)) {
>      TRACE("format expression failure");
> -    rc = SA_AIS_ERR_INVALID_PARAM;
> +    ais_rc = SA_AIS_ERR_INVALID_PARAM;
>      goto done;
>    }
> 
>    /* Verify if there is any special character in logFileName */
>    if (lgs_has_special_char(open_sync_param->logFileName) == true) {
>      TRACE("Invalid logFileName - %s", open_sync_param->logFileName);
> -    rc = SA_AIS_ERR_INVALID_PARAM;
> +    ais_rc = SA_AIS_ERR_INVALID_PARAM;
>      goto done;
>    }
> 
>    /* Verify if logFileName length is valid */
>    if (lgs_is_valid_filelength(open_sync_param->logFileName) == false) {
>      TRACE("logFileName is invalid");
> -    rc = SA_AIS_ERR_INVALID_PARAM;
> +    ais_rc = SA_AIS_ERR_INVALID_PARAM;
>      goto done;
>    }
> 
> @@ -902,7 +902,7 @@ SaAisErrorT
> create_new_app_stream(lgsv_stream_open_req_t *open_sync_param,
>    if (lgs_is_valid_pathlength(open_sync_param->logFilePathName,
>                                open_sync_param->logFileName) == false) {
>      TRACE("logFilePathName is invalid");
> -    rc = SA_AIS_ERR_INVALID_PARAM;
> +    ais_rc = SA_AIS_ERR_INVALID_PARAM;
>      goto done;
>    }
> 
> @@ -913,7 +913,7 @@ SaAisErrorT
> create_new_app_stream(lgsv_stream_open_req_t *open_sync_param,
>      if ((stream->fileName == open_sync_param->logFileName) &&
>          (stream->pathName == open_sync_param->logFilePathName)) {
>        TRACE("pathname already exist");
> -      rc = SA_AIS_ERR_INVALID_PARAM;
> +      ais_rc = SA_AIS_ERR_INVALID_PARAM;
>        goto done;
>      }
>    }
> @@ -922,7 +922,7 @@ SaAisErrorT
> create_new_app_stream(lgsv_stream_open_req_t *open_sync_param,
>    str_name = osaf_extended_name_borrow(&open_sync_param-
> >lstr_name);
>    if (strncmp(dnPrefix, str_name, strlen(dnPrefix)) != 0) {
>      TRACE("'%s' is not a valid stream name => invalid param", str_name);
> -    rc = SA_AIS_ERR_INVALID_PARAM;
> +    ais_rc = SA_AIS_ERR_INVALID_PARAM;
>      goto done;
>    }
> 
> @@ -933,13 +933,13 @@ SaAisErrorT
> create_new_app_stream(lgsv_stream_open_req_t *open_sync_param,
>        ((open_sync_param->maxLogRecordSize < SA_LOG_MIN_RECORD_SIZE)
> ||
>         (open_sync_param->maxLogRecordSize > logMaxLogrecsize_conf))) {
>      TRACE("maxLogRecordSize is invalid");
> -    rc = SA_AIS_ERR_INVALID_PARAM;
> +    ais_rc = SA_AIS_ERR_INVALID_PARAM;
>      goto done;
>    }
> 
>    *o_stream = log_stream_new(str_name, STREAM_NEW);
>    if (*o_stream == nullptr) {
> -    rc = SA_AIS_ERR_NO_MEMORY;
> +    ais_rc = SA_AIS_ERR_NO_MEMORY;
>      goto done;
>    }
> 
> @@ -951,16 +951,23 @@ SaAisErrorT
> create_new_app_stream(lgsv_stream_open_req_t *open_sync_param,
>        twelveHourModeFlag, 0, *o_stream);  // output
>    if (err == -1) {
>      log_stream_delete(o_stream);
> -    rc = SA_AIS_ERR_NO_MEMORY;
> +    ais_rc = SA_AIS_ERR_NO_MEMORY;
>      goto done;
>    }
> 
> -  rc = lgs_create_appstream_rt_object(*o_stream);
> -  if (rc != SA_AIS_OK) log_stream_delete(o_stream);
> +  ais_rc = lgs_create_appstream_rt_object(*o_stream);
> +  if (ais_rc != SA_AIS_OK) log_stream_delete(o_stream);
> +
> +  TRACE("%s: lgs_create_appstream_rt_object return, %s",
> +         __FUNCTION__, saf_error(ais_rc));
> +
> +  if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
> +    lgsOiCreateBackground();
> +  }
> 
>  done:
>    TRACE_LEAVE();
> -  return rc;
> +  return ais_rc;
>  }
> 
>  /**
> @@ -1069,15 +1076,7 @@ static uint32_t proc_stream_open_msg(lgs_cb_t
> *cb, lgsv_lgs_evt_t *evt) {
>        }
>      }
>    } else {
> -    /* Stream does not exist */
> -
> -    // This check is to avoid the client getting SA_AIS_BAD_OPERATION
> -    // as there is no IMM OI implementer set.
> -    if (cb->immOiHandle == 0) {
> -      TRACE("IMM service unavailable, open stream failed");
> -      ais_rv = SA_AIS_ERR_TRY_AGAIN;
> -      goto snd_rsp;
> -    }
> +    /* Stream does not exist. Create a new stream */
> 
>      /*
>       * Check if the stream is in the list of stream objects
> @@ -1125,6 +1124,11 @@ static uint32_t proc_stream_open_msg(lgs_cb_t
> *cb, lgsv_lgs_evt_t *evt) {
>      if (ais_rv != SA_AIS_OK) {
>        TRACE("%s create_new_app_stream Fail \"%s\"", __FUNCTION__,
>              saf_error(ais_rv));
> +      if (ais_rv == SA_AIS_ERR_BAD_HANDLE) {
> +        // This means that the stream RT object could not be created
because
> +        // of a bad OI handle. Change to TRY AGAIN in the reply to the
agent
> +        ais_rv = SA_AIS_ERR_TRY_AGAIN;
> +      }
>        goto snd_rsp;
>      }
>    }
> @@ -1218,7 +1222,7 @@ static uint32_t proc_stream_close_msg(lgs_cb_t
> *cb, lgsv_lgs_evt_t *evt) {
>    // This check is to avoid the client getting SA_AIS_BAD_OPERATION
>    // as there is no IMM OI implementer set.
>    if ((stream->streamType == STREAM_TYPE_APPLICATION_RT) &&
> -      (cb->immOiHandle == 0)) {
> +      (lgsGetOiHandle() == 0)) {
>      TRACE("IMM service unavailable, close stream failed");
>      ais_rc = SA_AIS_ERR_TRY_AGAIN;
>      goto snd_rsp;
> diff --git a/src/log/logd/lgs_imm.cc b/src/log/logd/lgs_imm.cc
> index 60870fa17..d23862172 100644
> --- a/src/log/logd/lgs_imm.cc
> +++ b/src/log/logd/lgs_imm.cc
> @@ -31,6 +31,8 @@
>  #define _GNU_SOURCE
>  #endif
> 
> +#include "log/logd/lgs_imm.h"
> +
>  #include <stdio.h>
>  #include <errno.h>
>  #include <string.h>
> @@ -46,6 +48,7 @@
>  #include "log/logd/lgs_recov.h"
>  #include "log/logd/lgs_config.h"
>  #include "log/logd/lgs_dest.h"
> +#include "log/logd/lgs_oi_admin.h"
>  #include "base/saf_error.h"
> 
>  #include "lgs_mbcsv_v1.h"
> @@ -58,11 +61,6 @@
>   * ----------------
>   */
> 
> -/* Used for protecting global imm OI handle and selection object during
> - * initialize of OI
> - */
> -pthread_mutex_t lgs_OI_init_mutex = PTHREAD_MUTEX_INITIALIZER;
> -
>  /* Used for checkpointing time when files are closed */
>  static time_t chkp_file_close_time = 0;
> 
> @@ -75,13 +73,6 @@ static const char *log_file_format[] = {
>      DEFAULT_ALM_NOT_FORMAT_EXP, DEFAULT_ALM_NOT_FORMAT_EXP,
>      DEFAULT_APP_SYS_FORMAT_EXP, DEFAULT_APP_SYS_FORMAT_EXP};
> 
> -static const SaImmOiImplementerNameT implementerName =
> -    const_cast<SaImmOiImplementerNameT>("safLogService");
> -static const SaImmClassNameT logConfig_str =
> -    const_cast<SaImmClassNameT>("OpenSafLogConfig");
> -static const SaImmClassNameT streamConfig_str =
> -    const_cast<SaImmClassNameT>("SaLogStreamConfig");
> -
>  // The list contains path-file names when validating its name in CCB
> completed
>  // callback. This help for log service prevents that creating any streams
>  // in same CCB with duplicated log path-file name
> @@ -2375,7 +2366,7 @@ static SaAisErrorT stream_create_and_configure1(
> 
>    /* Update creation timestamp */
>    rc = immutil_update_one_rattr(
> -      lgs_cb->immOiHandle, objectName.c_str(),
> +      lgsGetOiHandle(), objectName.c_str(),
>        const_cast<SaImmAttrNameT>("saLogStreamCreationTimestamp"),
>        SA_IMM_ATTR_SATIMET, &(*stream)->creationTimeStamp);
>    if (rc != SA_AIS_OK) {
> @@ -2702,7 +2693,7 @@ static SaAisErrorT
> rtAttrUpdateCallback(SaImmOiHandleT immOiHandle,
>    /* Handle configuration runtime object */
>    if (strncmp(objName, LGS_CFG_RUNTIME_OBJECT, strlen(objName)) == 0) {
>      /* Handle Runtome configuration object */
> -    conf_runtime_obj_hdl(immOiHandle, attributeNames);
> +    conf_runtime_obj_handler(immOiHandle, attributeNames);
>    } else {
>      /* Handle stream object if valid
>       */
> @@ -2889,11 +2880,15 @@ static const SaImmOiCallbacksT_2 callbacks = {
>      .saImmOiCcbObjectModifyCallback = ccbObjectModifyCallback,
>      .saImmOiRtAttrUpdateCallback = rtAttrUpdateCallback};
> 
> +// Export the callback structure. OI init is done in lgs_oi_admin
> +const SaImmOiCallbacksT_2* getImmOiCallbacks(void) {
> +  return &callbacks;
> +}
> +
>  /**
>   * Retrieve the LOG stream configuration from IMM using the
>   * IMM-OM interface and initialize the corresponding information
> - * in the LOG control block. Initialize the LOG IMM-OI
> - * interface. Become class implementer.
> + * in the LOG control block.
>   *
>   * @param cb[in] control block
>   * @return
> @@ -2987,20 +2982,6 @@ SaAisErrorT lgs_imm_init_configStreams(lgs_cb_t
> *cb) {
>      }
>    }
> 
> -  /* 1.Become implementer
> -   * 2.Update creation timestamp for all configure object, must be object
> -   * implementer first 3.Open all streams Config file and log file will
be
> -   * created. If this fails we give up without returning any error. A new
> -   * attempt to create the files will be done when trying to write a log
> -   * record to the stream.
> -   */
> -  ais_rc =
> -      immutil_saImmOiClassImplementerSet(cb->immOiHandle,
> "SaLogStreamConfig");
> -  if (ais_rc != SA_AIS_OK) {
> -    LOG_ER("immutil_saImmOiClassImplementerSet failed %s",
> saf_error(ais_rc));
> -    osaf_abort(0);
> -  }
> -
>    // Iterate all existing log streams in cluster.
>    while ((stream = iterate_all_streams(endloop, jstart)) && !endloop) {
>      jstart = SA_FALSE;
> @@ -3021,7 +3002,7 @@ SaAisErrorT lgs_imm_init_configStreams(lgs_cb_t
> *cb) {
>      }
> 
>      ais_rc = immutil_update_one_rattr(
> -        cb->immOiHandle, stream->name.c_str(),
> +        lgsGetOiHandle(), stream->name.c_str(),
>          const_cast<SaImmAttrNameT>("saLogStreamCreationTimestamp"),
>          SA_IMM_ATTR_SATIMET, &stream->creationTimeStamp);
>      if (ais_rc != SA_AIS_OK) {
> @@ -3046,255 +3027,6 @@ done:
>    return ais_rc;
>  }
> 
> -/**
> - * Initialize the OI interface and get a selection object.
> - * Become OI for safLogService if Active
> - *
> - * @param immOiHandle[out]
> - * @param immSelectionObject[out]
> - */
> -void lgs_imm_init_OI_handle(SaImmOiHandleT *immOiHandle,
> -                            SaSelectionObjectT *immSelectionObject) {
> -  SaAisErrorT rc;
> -  uint32_t msecs_waited = 0;
> -
> -  TRACE_ENTER();
> -
> -  /* Initialize IMM OI service */
> -  SaVersionT imm_version = kImmVersion;
> -  rc = saImmOiInitialize_2(immOiHandle, &callbacks, &imm_version);
> -  while ((rc == SA_AIS_ERR_TRY_AGAIN) &&
> -         (msecs_waited < max_waiting_time_60s)) {
> -    usleep(sleep_delay_ms * 1000);
> -    msecs_waited += sleep_delay_ms;
> -    imm_version = kImmVersion;
> -    rc = saImmOiInitialize_2(immOiHandle, &callbacks, &imm_version);
> -  }
> -  if (rc != SA_AIS_OK) {
> -    lgs_exit("saImmOiInitialize_2 failed", SA_AMF_COMPONENT_RESTART);
> -  }
> -
> -  /* Get selection object for event handling */
> -  msecs_waited = 0;
> -  rc = saImmOiSelectionObjectGet(*immOiHandle, immSelectionObject);
> -  while ((rc == SA_AIS_ERR_TRY_AGAIN) &&
> -         (msecs_waited < max_waiting_time_10s)) {
> -    usleep(sleep_delay_ms * 1000);
> -    msecs_waited += sleep_delay_ms;
> -    rc = saImmOiSelectionObjectGet(*immOiHandle, immSelectionObject);
> -  }
> -  if (rc != SA_AIS_OK) {
> -    lgs_exit("saImmOiSelectionObjectGet failed",
> SA_AMF_COMPONENT_RESTART);
> -  }
> -
> -  TRACE_LEAVE2("rc: %s", saf_error(rc));
> -}
> -
> -/**
> - * Does the sequence of setting an implementer name and class implementer
> - *
> - * @param immOiHandle[in]
> - * @return SaAisErrorT
> - */
> -static SaAisErrorT imm_impl_set_sequence(
> -    SaImmOiHandleT *immOiHandle, SaSelectionObjectT
> *immSelectionObject) {
> -  SaAisErrorT rc = SA_AIS_OK;
> -  uint32_t msecs_waited = 0;
> -
> -  TRACE_ENTER();
> -
> -  for (;;) {
> -    if (msecs_waited >= max_waiting_time_60s) {
> -      TRACE("Timeout in imm_impl_set_sequence");
> -      goto done;
> -    }
> -
> -    /* Become object implementer
> -     */
> -    rc = saImmOiImplementerSet(*immOiHandle, implementerName);
> -    while (((rc == SA_AIS_ERR_TRY_AGAIN) || (rc == SA_AIS_ERR_EXIST)) &&
> -           (msecs_waited < max_waiting_time_60s)) {
> -      usleep(sleep_delay_ms * 1000);
> -      msecs_waited += sleep_delay_ms;
> -      rc = saImmOiImplementerSet(*immOiHandle, implementerName);
> -    }
> -    if (rc == SA_AIS_ERR_BAD_HANDLE || rc == SA_AIS_ERR_TIMEOUT) {
> -      LOG_WA("saImmOiImplementerSet returned %s", saf_error(rc));
> -      usleep(sleep_delay_ms * 1000);
> -      msecs_waited += sleep_delay_ms;
> -      saImmOiFinalize(*immOiHandle);
> -      *immOiHandle = 0;
> -      *immSelectionObject = -1;
> -      lgs_imm_init_OI_handle(immOiHandle, immSelectionObject);
> -      continue;
> -    }
> -    if (rc != SA_AIS_OK) {
> -      TRACE("saImmOiImplementerSet failed %s", saf_error(rc));
> -      goto done;
> -    }
> -
> -    /*
> -     * Become class implementer for the OpenSafLogConfig class if it
exists
> -     * Become class implementer for the SaLogStreamConfig class
> -     */
> -    if (true == *static_cast<const bool *>(
> -
> lgs_cfg_get(LGS_IMM_LOG_OPENSAFLOGCONFIG_CLASS_EXIST))) {
> -      rc = saImmOiClassImplementerSet(*immOiHandle, logConfig_str);
> -      while (((rc == SA_AIS_ERR_TRY_AGAIN) || (rc == SA_AIS_ERR_EXIST))
&&
> -             (msecs_waited < max_waiting_time_60s)) {
> -        usleep(sleep_delay_ms * 1000);
> -        msecs_waited += sleep_delay_ms;
> -        rc = saImmOiClassImplementerSet(*immOiHandle, logConfig_str);
> -      }
> -      if (rc == SA_AIS_ERR_BAD_HANDLE || rc == SA_AIS_ERR_TIMEOUT) {
> -        LOG_WA("saImmOiClassImplementerSet returned %s", saf_error(rc));
> -        usleep(sleep_delay_ms * 1000);
> -        msecs_waited += sleep_delay_ms;
> -        saImmOiFinalize(*immOiHandle);
> -        *immOiHandle = 0;
> -        *immSelectionObject = -1;
> -        lgs_imm_init_OI_handle(immOiHandle, immSelectionObject);
> -        continue;
> -      }
> -      if (rc != SA_AIS_OK) {
> -        TRACE("saImmOiClassImplementerSet OpenSafLogConfig failed %s",
> -              saf_error(rc));
> -        goto done;
> -      }
> -    }
> -
> -    rc = saImmOiClassImplementerSet(*immOiHandle, streamConfig_str);
> -    while (((rc == SA_AIS_ERR_TRY_AGAIN) || (rc == SA_AIS_ERR_EXIST)) &&
> -           (msecs_waited < max_waiting_time_60s)) {
> -      usleep(sleep_delay_ms * 1000);
> -      msecs_waited += sleep_delay_ms;
> -      rc = saImmOiClassImplementerSet(*immOiHandle, streamConfig_str);
> -    }
> -    if (rc == SA_AIS_ERR_BAD_HANDLE || rc == SA_AIS_ERR_TIMEOUT) {
> -      LOG_WA("saImmOiClassImplementerSet returned %s", saf_error(rc));
> -      usleep(sleep_delay_ms * 1000);
> -      msecs_waited += sleep_delay_ms;
> -      saImmOiFinalize(*immOiHandle);
> -      *immOiHandle = 0;
> -      *immSelectionObject = -1;
> -      lgs_imm_init_OI_handle(immOiHandle, immSelectionObject);
> -      continue;
> -    }
> -    if (rc != SA_AIS_OK) {
> -      TRACE("saImmOiClassImplementerSet SaLogStreamConfig failed %s",
> -            saf_error(rc));
> -      goto done;
> -    }
> -    break;
> -  }
> -
> -done:
> -  TRACE_LEAVE2("rc: %s", saf_error(rc));
> -  return rc;
> -}
> -
> -/**
> - * Set implementer name and become class implementer.
> - * This function will block until done.
> - *
> - * @param cb
> - */
> -void lgs_imm_impl_set(SaImmOiHandleT *immOiHandle,
> -                      SaSelectionObjectT *immSelectionObject) {
> -  SaAisErrorT rc = SA_AIS_OK;
> -
> -  TRACE_ENTER();
> -
> -  rc = imm_impl_set_sequence(immOiHandle, immSelectionObject);
> -  if (rc != SA_AIS_OK) {
> -    lgs_exit("Becoming OI implementer failed",
> SA_AMF_COMPONENT_RESTART);
> -  }
> -
> -  TRACE_LEAVE();
> -}
> -
> -/**
> - * Thread
> - * Restore object and class implementer/applier.
> - *
> - * @param _cb[in]
> - */
> -static void *imm_impl_init_thread(void *_cb) {
> -  lgs_cb_t *cb = static_cast<lgs_cb_t *>(_cb);
> -  SaSelectionObjectT immSelectionObject = 0;
> -  SaImmOiHandleT immOiHandle = 0;
> -  SaAisErrorT rc = SA_AIS_OK;
> -
> -  TRACE_ENTER();
> -
> -  /* Initialize handles and become implementer */
> -  lgs_imm_init_OI_handle(&immOiHandle, &immSelectionObject);
> -  rc = imm_impl_set_sequence(&immOiHandle, &immSelectionObject);
> -  if (rc != SA_AIS_OK) {
> -    lgs_exit("Becoming OI implementer failed",
> SA_AMF_COMPONENT_RESTART);
> -  }
> -
> -  /* Store handle and selection object.
> -   * Protect if the poll loop in main is released during the storage
> -   * sequence.
> -   */
> -  osaf_mutex_lock_ordie(&lgs_OI_init_mutex);
> -  cb->immSelectionObject = immSelectionObject;
> -  cb->immOiHandle = immOiHandle;
> -  osaf_mutex_unlock_ordie(&lgs_OI_init_mutex);
> -
> -  /* Activate the poll loop in main()
> -   * This will reinstall IMM poll event handling
> -   */
> -  lgsv_lgs_evt_t *lgsv_evt;
> -  lgsv_evt = static_cast<lgsv_lgs_evt_t *>(calloc(1,
sizeof(lgsv_lgs_evt_t)));
> -  osafassert(lgsv_evt);
> -  lgsv_evt->evt_type = LGSV_EVT_NO_OP;
> -  if (m_NCS_IPC_SEND(&lgs_mbx, lgsv_evt, LGS_IPC_PRIO_CTRL_MSGS) !=
> -      NCSCC_RC_SUCCESS) {
> -    LOG_WA("imm_reinit_thread failed to send IPC message to main
thread");
> -    /*
> -     * Se no reason why this would happen. But if it does at least there
> -     * is something in the syslog. The main thread should still pick up
> -     * the new imm FD when there is a healthcheck, but it could take
> -     *minutes.
> -     */
> -    free(lgsv_evt);
> -  }
> -
> -  TRACE_LEAVE();
> -  return NULL;
> -}
> -
> -/**
> - * In a separate thread:
> - * Initiate IMM OI handle and selection object
> - * Create imm implementer for log IMM objects
> - * When complete:
> - * Store the new handle and selection object in the cb store.
> - * Activate the poll loop in main() by sending an empty mailbox message
> - *
> - * @param cb[out]
> - */
> -void lgs_imm_impl_reinit_nonblocking(lgs_cb_t *cb) {
> -  pthread_t thread;
> -  pthread_attr_t attr;
> -
> -  TRACE_ENTER();
> -
> -  pthread_attr_init(&attr);
> -  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
> -
> -  if (pthread_create(&thread, &attr, imm_impl_init_thread, cb) != 0) {
> -    LOG_ER("pthread_create FAILED: %s", strerror(errno));
> -    exit(EXIT_FAILURE);
> -  }
> -
> -  pthread_attr_destroy(&attr);
> -
> -  TRACE_LEAVE();
> -}
> -
> 
> /**************************************************************
> ****************
>   * Functions used for recovery handling
> 
> **************************************************************
> ****************/
> @@ -3403,12 +3135,16 @@ void lgs_delete_one_stream_object(const
> std::string &name_str) {
>    osaf_extended_name_lend(name_str.c_str(), &object_name);
> 
>    /* and delete the object */
> -  ais_rc = immutil_saImmOiRtObjectDelete(lgs_cb->immOiHandle,
> &object_name);
> +  ais_rc = immutil_saImmOiRtObjectDelete(lgsGetOiHandle(),
> &object_name);
>    if (ais_rc == SA_AIS_OK) {
>      TRACE("%s Object \"%s\" deleted", __FUNCTION__, name_str.c_str());
> +  } else if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
> +    LOG_NO("%s: saImmOiRtObjectDelete() Fail, %s", __FUNCTION__,
> +           saf_error(ais_rc));
> +    lgsOiCreateBackground();
>    } else {
> -    LOG_WA("%s saImmOiRtObjectDelete for \"%s\" FAILED %d",
> __FUNCTION__,
> -           name_str.c_str(), ais_rc);
> +    LOG_WA("%s saImmOiRtObjectDelete for \"%s\" FAILED %s",
> __FUNCTION__,
> +           name_str.c_str(), saf_error(ais_rc));
>    }
>  }
> 
> @@ -3444,12 +3180,16 @@ void lgs_cleanup_abandoned_streams() {
>        /* Copy name to a SaNameT */
>        osaf_extended_name_lend(name_str, &object_name);
>        /* and delete the object */
> -      ais_rc = immutil_saImmOiRtObjectDelete(lgs_cb->immOiHandle,
> &object_name);
> +      ais_rc = immutil_saImmOiRtObjectDelete(lgsGetOiHandle(),
> &object_name);
>        if (ais_rc == SA_AIS_OK) {
>          TRACE("\tObject \"%s\" deleted", name_str);
> +      } else if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
> +        LOG_WA("%s saImmOiRtObjectDelete for \"%s\" FAILED %s",
> __FUNCTION__,
> +               name_str, saf_error(ais_rc));
> +        lgsOiCreateBackground();
>        } else {
> -        LOG_WA("%s saImmOiRtObjectDelete for \"%s\" FAILED %d",
> __FUNCTION__,
> -               name_str, ais_rc);
> +        LOG_WA("%s saImmOiRtObjectDelete for \"%s\" FAILED %s",
> __FUNCTION__,
> +               name_str, saf_error(ais_rc));
>        }
>      } else {
>        /* Should never happen! */
> diff --git a/src/log/logd/lgs_imm.h b/src/log/logd/lgs_imm.h
> new file mode 100644
> index 000000000..195d09380
> --- /dev/null
> +++ b/src/log/logd/lgs_imm.h
> @@ -0,0 +1,53 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2008 The OpenSAF Foundation
> + * Copyright Ericsson AB 2008, 2018 - All Rights Reserved.
> + *
> + * 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_IMM_H
> +#define LGS_IMM_H
> +
> +#include <time.h>
> +#include <string>
> +
> +#include "ais/include/saImmOi.h"
> +#include "ais/include/saImmOm.h"
> +
> +#include "log/logd/lgs_cb.h"
> +
> +// Get the callback structure used when initializing an OI handle
> +const SaImmOiCallbacksT_2* getImmOiCallbacks(void);
> +
> +void logRootDirectory_filemove(const std::string &new_logRootDirectory,
> +                                      const std::string
&old_logRootDirectory,
> +                                      time_t *cur_time_in);
> +void logDataGroupname_fileown(const char *new_logDataGroupname);
> +
> +SaAisErrorT lgs_imm_init_configStreams(lgs_cb_t *cb);
> +
> +// Functions for recovery handling
> +void lgs_cleanup_abandoned_streams();
> +void lgs_delete_one_stream_object(const std::string &name_str);
> +void lgs_search_stream_objects();
> +SaUint32T *lgs_get_scAbsenceAllowed_attr(SaUint32T *attr_val);
> +int lgs_get_streamobj_attr(SaImmAttrValuesT_2 ***attrib_out,
> +                           const std::string &object_name,
> +                           SaImmHandleT *immOmHandle);
> +int lgs_free_streamobj_attr(SaImmHandleT immHandle);
> +
> +
> +
> +#endif /* LGS_IMM_H */
> +
> diff --git a/src/log/logd/lgs_main.cc b/src/log/logd/lgs_main.cc
> index 988ebdd78..9767fe00d 100644
> --- a/src/log/logd/lgs_main.cc
> +++ b/src/log/logd/lgs_main.cc
> @@ -33,16 +33,18 @@
>  #include "nid/agent/nid_api.h"
>  #include "base/ncs_main_papi.h"
>  #include "base/osaf_time.h"
> -
> -#include "log/logd/lgs.h"
> -#include "log/logd/lgs_file.h"
>  #include "base/osaf_utility.h"
>  #include "base/hash.h"
> -#include "lgs_recov.h"
>  #include "osaf/immutil/immutil.h"
> +
> +#include "log/logd/lgs.h"
> +#include "log/logd/lgs_file.h"
> +#include "log/logd/lgs_recov.h"
>  #include "lgs_clm.h"
>  #include "log/logd/lgs_dest.h"
>  #include "log/logd/lgs_amf.h"
> +#include "log/logd/lgs_oi_admin.h"
> +#include "log/logd/lgs_imm.h"
> 
> 
>  /*
> ==============================================================
> ==========
> @@ -383,26 +385,21 @@ uint32_t initialize_for_assignment(lgs_cb_t *cb,
> SaAmfHAStateT ha_state) {
>    if (cb->fully_initialized || ha_state == SA_AMF_HA_QUIESCED) goto done;
>    cb->ha_state = ha_state;
> 
> -  /* Initialize IMM OI handle and selection object */
> -  lgs_imm_init_OI_handle(&cb->immOiHandle, &cb->immSelectionObject);
> -
> -  TRACE("IMM init done: cb->immOiHandle = %lld", cb->immOiHandle);
> -
>    /* Initialize log configuration
>     * Must be done after IMM OI is initialized
>     */
> -  lgs_cfg_init(cb->immOiHandle, cb->ha_state);
> +  lgs_cfg_init();
>    lgs_trace_config(); /* Show all configuration in TRACE */
> 
> -  /* Show some configurtion info in sysylog */
> -  logsv_root_dir =
> -      static_cast<const char
> *>(lgs_cfg_get(LGS_IMM_LOG_ROOT_DIRECTORY));
> -  logsv_data_groupname =
> -      static_cast<const char *>(lgs_cfg_get(LGS_IMM_DATA_GROUPNAME));
> +  /* Show some configuration info in sysylog */
> +  logsv_root_dir = static_cast<const char *>
> +                   (lgs_cfg_get(LGS_IMM_LOG_ROOT_DIRECTORY));
> +  logsv_data_groupname = static_cast<const char *>
> +                         (lgs_cfg_get(LGS_IMM_DATA_GROUPNAME));
>    LOG_NO("LOG root directory is: \"%s\"", logsv_root_dir);
>    LOG_NO("LOG data group is: \"%s\"", logsv_data_groupname);
> -  vdest = reinterpret_cast<const std::vector<std::string> *>(
> -      lgs_cfg_get(LGS_IMM_LOG_RECORD_DESTINATION_CONFIGURATION));
> +  vdest = reinterpret_cast<const std::vector<std::string> *>
> +
> (lgs_cfg_get(LGS_IMM_LOG_RECORD_DESTINATION_CONFIGURATION));
>    osafassert(vdest != nullptr);
>    if (vdest->size() > 0) {
>      CfgDestination(*vdest, ModifyType::kAdd);
> @@ -445,20 +442,15 @@ uint32_t initialize_for_assignment(lgs_cb_t *cb,
> SaAmfHAStateT ha_state) {
>    }
> 
>    if (ha_state == SA_AMF_HA_ACTIVE) {
> -    /* Become OI. We will be blocked here until done */
> -    lgs_imm_impl_set(&cb->immOiHandle, &cb->immSelectionObject);
> -    conf_runtime_obj_create(cb->immOiHandle);
> +    // Request an Object Implementer, a configuration object handler and
> +    // an applier for opensafNetworkName change surveillance
> +    lgsOiCreateSynchronous();
> +    conf_runtime_obj_create(lgsGetOiHandle());
>      lgs_start_gcfg_applier();
> 
> -    /* Create streams that has configuration objects and become
> -     * class implementer for the SaLogStreamConfig class
> -     */
> -
> -    /* Note1: cb->immOiHandle is set in lgs_imm_init()
> -     * Note2: cb->logsv_root_dir must be set
> -     */
> +    // Create streams that has configuration objects
>      if (lgs_imm_init_configStreams(cb) != SA_AIS_OK) {
> -      LOG_ER("lgs_imm_create_configStream FAILED");
> +      LOG_ER("lgs_imm_create_configStreams FAILED");
>        rc = NCSCC_RC_FAILURE;
>        goto done;
>      }
> @@ -479,7 +471,7 @@ done:
>   */
>  int main(int argc, char *argv[]) {
>    NCS_SEL_OBJ mbx_fd;
> -  SaAisErrorT error = SA_AIS_OK;
> +  SaAisErrorT ais_rc = SA_AIS_OK;
>    uint32_t rc;
>    int term_fd;
> 
> @@ -519,7 +511,7 @@ int main(int argc, char *argv[]) {
>    fds[FD_AMF].events = POLLIN;
>    fds[FD_MBX].fd = mbx_fd.rmv_obj;
>    fds[FD_MBX].events = POLLIN;
> -  fds[FD_IMM].fd = lgs_cb->immSelectionObject;
> +  fds[FD_IMM].fd = lgsGetOiSelectionObject();
>    fds[FD_IMM].events = POLLIN;
> 
>    lgs_cb->clmSelectionObject = lgs_cb->clm_init_sel_obj.rmv_obj;
> @@ -539,18 +531,16 @@ int main(int argc, char *argv[]) {
>      fds[FD_CLM].fd = lgs_cb->clmSelectionObject;
>      fds[FD_CLM].events = POLLIN;
> 
> -    /* Protect since the reinit thread may be in the process of
> -     * changing the values
> -     */
> -    osaf_mutex_lock_ordie(&lgs_OI_init_mutex);
> -    if (lgs_cb->immOiHandle != 0) {
> -      fds[FD_IMM].fd = lgs_cb->immSelectionObject;
> +    // Adds or removes the IMM fd depending on if there is an OI or not
> +    SaImmOiHandleT oi_handle;
> +    SaSelectionObjectT oi_selection_object =
> lgsGetOiFdsParams(&oi_handle);
> +    if (oi_handle != 0) {
> +      fds[FD_IMM].fd = oi_selection_object;
>        fds[FD_IMM].events = POLLIN;
>        nfds = FD_IMM + 1;
>      } else {
>        nfds = FD_IMM;
>      }
> -    osaf_mutex_unlock_ordie(&lgs_OI_init_mutex);
> 
>      int ret = poll(fds, nfds, -1);
> 
> @@ -567,9 +557,9 @@ int main(int argc, char *argv[]) {
> 
>      if (fds[FD_AMF].revents & POLLIN) {
>        if (lgs_cb->amf_hdl != 0) {
> -        if ((error = saAmfDispatch(lgs_cb->amf_hdl, SA_DISPATCH_ALL)) !=
> +        if ((ais_rc = saAmfDispatch(lgs_cb->amf_hdl, SA_DISPATCH_ALL)) !=
>              SA_AIS_OK) {
> -          LOG_ER("saAmfDispatch failed: %u", error);
> +          LOG_ER("saAmfDispatch failed: %u", ais_rc);
>            break;
>          }
>        } else {
> @@ -593,9 +583,9 @@ int main(int argc, char *argv[]) {
> 
>      if (fds[FD_CLM].revents & POLLIN) {
>        if (lgs_cb->clm_hdl != 0) {
> -        if ((error = saClmDispatch(lgs_cb->clm_hdl, SA_DISPATCH_ALL)) !=
> +        if ((ais_rc = saClmDispatch(lgs_cb->clm_hdl, SA_DISPATCH_ALL)) !=
>              SA_AIS_OK) {
> -          LOG_ER("saClmDispatch failed: %u", error);
> +          LOG_ER("saClmDispatch failed: %u", ais_rc);
>            break;
>          }
>        } else {
> @@ -629,40 +619,16 @@ int main(int argc, char *argv[]) {
> 
>      if (fds[FD_MBX].revents & POLLIN) lgs_process_mbx(&lgs_mbx);
> 
> -    if (lgs_cb->immOiHandle && fds[FD_IMM].revents & POLLIN) {
> -      error = saImmOiDispatch(lgs_cb->immOiHandle, SA_DISPATCH_ALL);
> -
> -      /*
> -       * BAD_HANDLE is interpreted as an IMM service restart. Try
> -       * reinitialize the IMM OI API in a background thread and let
> -       * this thread do business as usual especially handling write
> -       * requests.
> -       *
> -       * All other errors are treated as non-recoverable (fatal) and will
> -       * cause an exit of the process.
> -       */
> -      if (error == SA_AIS_ERR_BAD_HANDLE) {
> -        TRACE("saImmOiDispatch returned BAD_HANDLE");
> -
> -        /*
> -         * Invalidate the IMM OI handle, this info is used in other
> -         * locations. E.g. giving TRY_AGAIN responses to a create and
> -         * close app stream requests. That is needed since the IMM OI
> -         * is used in context of these functions.
> -         *
> -         * Also closing the handle. Finalize is ok with a bad handle
> -         * that is bad because it is stale and this actually clears
> -         * the handle from internal agent structures.  In any case
> -         * we ignore the return value from Finalize here.
> -         */
> -        saImmOiFinalize(lgs_cb->immOiHandle);
> -        lgs_cb->immOiHandle = 0;
> -        lgs_cb->immSelectionObject = -1;
> -
> -        /* Initiate IMM reinitializtion in the background */
> -        lgs_imm_impl_reinit_nonblocking(lgs_cb);
> -      } else if (error != SA_AIS_OK) {
> -        LOG_ER("saImmOiDispatch FAILED: %u", error);
> +    if (fds[FD_IMM].revents & POLLIN) {
> +      ais_rc = saImmOiDispatch(lgsGetOiHandle(), SA_DISPATCH_ALL);
> +
> +      if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
> +        LOG_NO("saImmOiDispatch returned BAD_HANDLE");
> +
> +        // Request creation of a new OI
> +        lgsOiCreateBackground();
> +      } else if (ais_rc != SA_AIS_OK) {
> +        LOG_ER("saImmOiDispatch FAILED: %u", ais_rc);
>          break;
>        }
>      }
> diff --git a/src/log/logd/lgs_mbcsv_v2.cc b/src/log/logd/lgs_mbcsv_v2.cc
> index 9afc30155..63807e1b7 100644
> --- a/src/log/logd/lgs_mbcsv_v2.cc
> +++ b/src/log/logd/lgs_mbcsv_v2.cc
> @@ -21,9 +21,10 @@
>   * version 2 check-pointing. See also lgs_mbcsv_v2.h
>   */
> 
> -#include "lgs_config.h"
> -#include "lgs_mbcsv_v2.h"
> -#include "lgs_mbcsv.h"
> +#include "log/logd/lgs_config.h"
> +#include "log/logd/lgs_imm.h"
> +#include "log/logd/lgs_mbcsv_v2.h"
> +#include "log/logd/lgs_mbcsv.h"
> 
> 
> /**************************************************************
> **************
>   * Name          : ckpt_proc_lgs_cfg
> diff --git a/src/log/logd/lgs_mbcsv_v3.cc b/src/log/logd/lgs_mbcsv_v3.cc
> index f9836c8af..75fd98dba 100644
> --- a/src/log/logd/lgs_mbcsv_v3.cc
> +++ b/src/log/logd/lgs_mbcsv_v3.cc
> @@ -21,9 +21,10 @@
>   * version 3 check-pointing. See also lgs_mbcsv_v3.h
>   */
> 
> -#include "lgs_mbcsv_v3.h"
> -#include "lgs_mbcsv_v2.h"
> -#include "lgs_mbcsv.h"
> +#include "log/logd/lgs_imm.h"
> +#include "log/logd/lgs_mbcsv_v3.h"
> +#include "log/logd/lgs_mbcsv_v2.h"
> +#include "log/logd/lgs_mbcsv.h"
> 
> 
> /**************************************************************
> **************
>   * Name          : ckpt_proc_lgs_cfg
> diff --git a/src/log/logd/lgs_mbcsv_v5.cc b/src/log/logd/lgs_mbcsv_v5.cc
> index 75d627688..d219f8a5b 100644
> --- a/src/log/logd/lgs_mbcsv_v5.cc
> +++ b/src/log/logd/lgs_mbcsv_v5.cc
> @@ -22,8 +22,9 @@
>   * V5 applies to log server configuration check-pointing
>   */
> 
> -#include "lgs_mbcsv_v5.h"
>  #include "log/logd/lgs_dest.h"
> +#include "log/logd/lgs_imm.h"
> +#include "log/logd/lgs_mbcsv_v5.h"
> 
> 
> /**************************************************************
> **************
>   * Name          : ckpt_proc_lgs_cfg
> diff --git a/src/log/logd/lgs_oi_admin.cc b/src/log/logd/lgs_oi_admin.cc
> new file mode 100644
> index 000000000..abd74c816
> --- /dev/null
> +++ b/src/log/logd/lgs_oi_admin.cc
> @@ -0,0 +1,461 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2008 The OpenSAF Foundation
> + * Copyright Ericsson AB 2008, 2018 - All Rights Reserved.
> + *
> + * 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 "log/logd/lgs_oi_admin.h"
> +
> +#include <atomic>
> +#include <thread>
> +
> +#include "ais/include/saAis.h"
> +#include "ais/include/saImmOi.h"
> +#include "base/logtrace.h"
> +#include "base/mutex.h"
> +#include "base/saf_error.h"
> +#include "base/time.h"
> +
> +#include "log/logd/lgs.h"
> +#include "log/logd/lgs_imm.h"
> +#include "log/logd/lgs_config.h"
> +#include "log/logd/lgs_util.h"
> +
> +// Note: Always use the set and get function with these varibales
> +static base::Mutex lgs_OI_init_mutex;
> +static SaImmOiHandleT oi_handle_ = 0;
> +static SaSelectionObjectT oi_selection_object_ = -1;
> +
> +static const SaImmOiImplementerNameT kImplementerName =
> +    const_cast<SaImmOiImplementerNameT>("safLogService");
> +// The log server is OI for the following configuration classes
> +static const SaImmClassNameT kLogConfigurationClass =
> +    const_cast<SaImmClassNameT>("OpenSafLogConfig");
> +static const SaImmClassNameT kLogStreamClass =
> +    const_cast<SaImmClassNameT>("SaLogStreamConfig");
> +
> +static const uint64_t kOiCreationTimeout = 90000;  // 1.5 minutes
> +static const uint64_t kOiHandleRequestTimeout = 60000;  // 1 minute
> +static const uint64_t kOiRequestTimeout = 10000;  // 10 sec generic
timeout
> +static const timespec kOiTryAgainDelay = base::kOneHundredMilliseconds;
> +
> +// Internal help functions
> +// ---------------------------------
> +
> +static void setProtectedGlobals(SaImmOiHandleT oi_handle,
> +                                SaSelectionObjectT oi_selction_object) {
> +  TRACE_ENTER();
> +  base::Lock protect_globals(lgs_OI_init_mutex);
> +  oi_handle_ = oi_handle;
> +  oi_selection_object_ = oi_selction_object;
> +}
> +
> +static SaAisErrorT finalizeOi(SaImmOiHandleT oi_handle) {
> +  TRACE_ENTER();
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  base::Timer try_again_timer(kOiRequestTimeout);
> +  while (try_again_timer.is_timeout() == false) {
> +    ais_rc = saImmOiFinalize(oi_handle);
> +    if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +      base::Sleep(kOiTryAgainDelay);
> +      continue;
> +    }
> +    if (ais_rc != SA_AIS_OK) {
> +      TRACE("%s: saImmOiFinalize() Fail, %s", __FUNCTION__,
> saf_error(ais_rc));
> +    }
> +    break;
> +  }
> +  if ((try_again_timer.is_timeout() == true) &&
> +      (ais_rc == SA_AIS_ERR_TRY_AGAIN)) {
> +    LOG_NO("%s: saImmOiFinalize() Fail, TRY AGAIN timeout",
> __FUNCTION__);
> +  }
> +
> +  return ais_rc;
> +}
> +
> +// IMM API help function used in the OI creation thread
> +// Communication flag read in OI thread and set by the lgs_OI_delete()
and
> +// create functions. When this flag is true the thread shall stop and
return
> +// as soon as possible
> +// Note: All of these functions will stop internal loops and return if
> +// the global atomic flag oi_stop == true
> +static std::atomic<bool> stop_oi_create(false);
> +
> +// Output: out_oi_handle. Set to 0 if fail
> +static SaAisErrorT initOiHandle(SaImmOiHandleT *out_oi_handle) {
> +  TRACE_ENTER();
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  const SaImmOiCallbacksT_2 *callbacks = getImmOiCallbacks();
> +  base::Timer try_again_timer(kOiHandleRequestTimeout);
> +  while (try_again_timer.is_timeout() == false) {
> +    if (stop_oi_create) {
> +      ais_rc = SA_AIS_OK;
> +      break;
> +    }
> +    SaVersionT imm_version = kImmVersion;
> +    ais_rc = saImmOiInitialize_2(out_oi_handle, callbacks, &imm_version);
> +    if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +      base::Sleep(kOiTryAgainDelay);
> +      continue;
> +    }
> +    if (ais_rc != SA_AIS_OK) {
> +      LOG_WA("%s: saImmOiInitialize_2() Fail, %s", __FUNCTION__,
> +            saf_error(ais_rc));
> +      *out_oi_handle = 0;
> +    }
> +    break;
> +  }
> +  if ((try_again_timer.is_timeout() == true) &&
> +      (ais_rc == SA_AIS_ERR_TRY_AGAIN)) {
> +    LOG_WA("%s: saImmOiInitialize_2() Fail, TRY AGAIN timeout",
> __FUNCTION__);
> +    *out_oi_handle = 0;
> +  }
> +
> +  return ais_rc;
> +}
> +
> +// Return -1 if Fail
> +// out_ais_rc is set to return code from saImmOiSelectionObjectGet()
> +static SaSelectionObjectT requestOiSelectionObject(SaImmOiHandleT
> oi_handle,
> +                                                   SaAisErrorT*
out_ais_rc) {
> +  TRACE_ENTER();
> +  SaSelectionObjectT oi_selection_object = -1;
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  base::Timer try_again_timer(kOiRequestTimeout);
> +  while (try_again_timer.is_timeout() == false) {
> +    if (stop_oi_create) {
> +      oi_selection_object = -1;
> +      break;
> +    }
> +    ais_rc = saImmOiSelectionObjectGet(oi_handle, &oi_selection_object);
> +    if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +      base::Sleep(kOiTryAgainDelay);
> +      continue;
> +    }
> +    if (ais_rc != SA_AIS_OK) {
> +      LOG_WA("%s: saImmOiSelectionObjectGet() Fail, %s", __FUNCTION__,
> +             saf_error(ais_rc));
> +      oi_selection_object = -1;
> +    }
> +    break;
> +  }
> +  if ((try_again_timer.is_timeout() == true) &&
> +      (ais_rc == SA_AIS_ERR_TRY_AGAIN)) {
> +    LOG_WA("%s: saImmOiSelectionObjectGet() Fail, TRY AGAIN timeout",
> +           __FUNCTION__);
> +    oi_selection_object = -1;
> +  }
> +
> +  *out_ais_rc = ais_rc;
> +  return oi_selection_object;
> +}
> +
> +// Set implementer name in kImplementerName
> +static SaAisErrorT setOiImplementerName(SaImmOiHandleT oi_handle) {
> +  TRACE_ENTER();
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  base::Timer try_again_timer(kOiRequestTimeout);
> +  while (try_again_timer.is_timeout() == false) {
> +    if (stop_oi_create) {
> +      ais_rc = SA_AIS_OK;
> +      break;
> +    }
> +    ais_rc = saImmOiImplementerSet(oi_handle, kImplementerName);
> +    if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +      base::Sleep(kOiTryAgainDelay);
> +      continue;
> +    }
> +    if (ais_rc == SA_AIS_ERR_EXIST) {
> +      // Means that we already have the implementer name registered which
> is Ok
> +      TRACE("%s saImmOiImplementerSet() Fail %s. Ignore",
> +             __FUNCTION__, saf_error(ais_rc));
> +      ais_rc = SA_AIS_OK;
> +      break;
> +    } else if (ais_rc != SA_AIS_OK) {
> +      LOG_WA("%s: saImmOiImplementerSet() Fail, %s", __FUNCTION__,
> +             saf_error(ais_rc));
> +    }
> +    break;
> +  }
> +  if ((try_again_timer.is_timeout() == true) &&
> +      (ais_rc == SA_AIS_ERR_TRY_AGAIN)) {
> +    LOG_WA("%s: saImmOiImplementerSet() Fail, TRY AGAIN timeout",
> +           __FUNCTION__);
> +  }
> +
> +  TRACE_LEAVE2("ais_rc = %s", saf_error(ais_rc));
> +  return ais_rc;
> +}
> +
> +static SaAisErrorT setClassImplementer(SaImmOiHandleT oi_handle,
> +                                       const SaImmClassNameT class_name)
{
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  base::Timer try_again_timer(kOiRequestTimeout);
> +  while (try_again_timer.is_timeout() == false) {
> +    if (stop_oi_create) {
> +      ais_rc = SA_AIS_OK;
> +      break;
> +    }
> +    ais_rc = saImmOiClassImplementerSet(oi_handle, class_name);
> +    if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +      base::Sleep(kOiTryAgainDelay);
> +      continue;
> +    }
> +    if (ais_rc != SA_AIS_OK) {
> +      LOG_WA("%s: saImmOiClassImplementerSet() Fail, %s", __FUNCTION__,
> +             saf_error(ais_rc));
> +    }
> +    break;
> +  }
> +  if ((try_again_timer.is_timeout() == true) &&
> +      (ais_rc == SA_AIS_ERR_TRY_AGAIN)) {
> +    LOG_WA("%s: saImmOiClassImplementerSet() Fail, TRY AGAIN timeout",
> +           __FUNCTION__);
> +  }
> +
> +  return ais_rc;
> +}
> +
> +// Activate the poll loop in main()
> +// This will reinstall IMM poll event handling
> +static void sendOiCreatedMessageToMainThread() {
> +  TRACE_ENTER();
> +  // Note: lgsv_evt must be allocated C style since it will be freed in
other
> +  //       part of the code with free()
> +  lgsv_lgs_evt_t *lgsv_evt;
> +  lgsv_evt = static_cast<lgsv_lgs_evt_t *>(calloc(1,
sizeof(lgsv_lgs_evt_t)));
> +  osafassert(lgsv_evt);
> +
> +  lgsv_evt->evt_type = LGSV_EVT_NO_OP;
> +  if (m_NCS_IPC_SEND(&lgs_mbx, lgsv_evt, LGS_IPC_PRIO_CTRL_MSGS) !=
> +      NCSCC_RC_SUCCESS) {
> +    LOG_WA("imm_reinit_thread failed to send IPC message to main
> thread");
> +    /*
> +     * Se no reason why this would happen. But if it does at least there
> +     * is something in the syslog. The main thread should still pick up
> +     * the new imm FD when there is a healthcheck, but it could take
> +     *minutes.
> +     */
> +    free(lgsv_evt);
> +  }
> +}
> +
> +// Creates the log service OI
> +// stop_oi_create:  Used to stop thread execution as soon as possible
> +//                  Will stop the thread when set to true.
> +static SaAisErrorT createLogServerOi() {
> +  TRACE_ENTER();
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  SaImmOiHandleT oi_handle = 0;
> +  SaSelectionObjectT oi_selection_object = -1;
> +  base::Timer io_create_timeout(kOiCreationTimeout);
> +
> +  while (io_create_timeout.is_timeout() == false) {
> +    // OI init sequence
> +
> +    // Init OI handle
> +    if (stop_oi_create) break;
> +    ais_rc = initOiHandle(&oi_handle);
> +    if (ais_rc != SA_AIS_OK) {
> +      LOG_NO("%s: initOiHandle() Fail", __FUNCTION__);
> +      oi_handle = 0;
> +      break;
> +    }
> +
> +    // Set OI implementer name
> +    if (stop_oi_create) break;
> +    ais_rc = setOiImplementerName(oi_handle);
> +    if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
> +      TRACE("%s: setOiImplementerName() Fail %s. Try to recover",
> +            __FUNCTION__, saf_error(ais_rc));
> +      continue;
> +    } else if (ais_rc != SA_AIS_OK) {
> +      LOG_NO("%s: setOiImplementerName() Fail", __FUNCTION__);
> +      break;
> +    }
> +
> +    // Become class implementer for log config class
> +    if (stop_oi_create) break;
> +    ais_rc = setClassImplementer(oi_handle, kLogConfigurationClass);
> +    if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
> +      TRACE("%s: setClassImplementer(LogConfigurationClass) Fail %s. "
> +            "Try to recover", __FUNCTION__, saf_error(ais_rc));
> +      continue;
> +    } else if (ais_rc != SA_AIS_OK) {
> +      LOG_NO("%s: setClassImplementer(LogConfigurationClass) Fail",
> +             __FUNCTION__);
> +      break;
> +    }
> +
> +    // Become class implementer for stream config class
> +    if (stop_oi_create) break;
> +    ais_rc = setClassImplementer(oi_handle, kLogStreamClass);
> +    if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
> +      TRACE("%s: setClassImplementer(kLogStreamClass) Fail %s. "
> +            "Try to recover", __FUNCTION__, saf_error(ais_rc));
> +      continue;
> +    } else if (ais_rc != SA_AIS_OK) {
> +      LOG_NO("%s: setClassImplementer(kLogStreamClass) Fail",
> __FUNCTION__);
> +      break;
> +    } else {
> +      // Get the selection object
> +      oi_selection_object = requestOiSelectionObject(oi_handle, &ais_rc);
> +      if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
> +        TRACE("%s: requestOiSelectionObject() Fail", __FUNCTION__);
> +      }
> +      break;
> +    }
> +  }
> +
> +  // Creation is done, has failed or is stopped.
> +  if (stop_oi_create) {
> +    TRACE("%s: OI create is stopped", __FUNCTION__);
> +    oi_handle = 0;
> +    oi_selection_object = -1;
> +    ais_rc = SA_AIS_ERR_NO_OP;  // Dummy. Must not be SA_AIS_OK
> +  } else if ((io_create_timeout.is_timeout() == true) &&
> +             (ais_rc != SA_AIS_OK)) {
> +    LOG_WA("%s: Fail, OI creation timeout", __FUNCTION__);
> +#if 0  // Note: The following is needed if some other recovery than
restart
> +    oi_handle = 0;
> +    oi_selection_object = -1;
> +#endif
> +    // The legacy behavior is to exit log service in this case
> +    lgs_exit("saImmOiInitialize_2 failed", SA_AMF_COMPONENT_RESTART);
> +  } else if (ais_rc != SA_AIS_OK) {
> +    LOG_WA("%s: Fail, OI creation error", __FUNCTION__);
> +#if 0  // Note: The following is needed if some other recovery than
restart
> +    oi_handle = 0;
> +    oi_selection_object = -1;
> +#endif
> +    // The legacy behavior is to exit log service in this case
> +    lgs_exit("saImmOiInitialize_2 failed", SA_AMF_COMPONENT_RESTART);
> +  }
> +
> +  // Save OI handle and selection object
> +  setProtectedGlobals(oi_handle, oi_selection_object);
> +
> +  return ais_rc;
> +}
> +
> +// The thread function for creating a log server OI
> +// stop_oi_create:  Used to stop thread execution as soon as possible
> +//                  Will stop the thread when set to true.
> +static void oiCreationThread() {
> +  TRACE_ENTER();
> +  SaAisErrorT ais_rc = createLogServerOi();
> +
> +  if (ais_rc == SA_AIS_OK) {
> +    // An object implementer was successfully created
> +    // Send a message to the main thread. IMM events shall be polled
again
> +    sendOiCreatedMessageToMainThread();
> +  }
> +
> +  return;
> +}
> +
> +// Public functions
> +//-----------------
> +// Make the thread class available for create and delete
> +static std::thread oiCreationThread_ {};
> +
> +
> +SaImmOiHandleT lgsGetOiHandle() {
> +  base::Lock protect_globals(lgs_OI_init_mutex);
> +  return oi_handle_;
> +}
> +
> +SaSelectionObjectT lgsGetOiSelectionObject() {
> +  base::Lock protect_globals(lgs_OI_init_mutex);
> +  return oi_selection_object_;
> +}
> +
> +SaSelectionObjectT lgsGetOiFdsParams(SaImmOiHandleT* out_oi_handle) {
> +  base::Lock protect_globals(lgs_OI_init_mutex);
> +  *out_oi_handle = oi_handle_;
> +  return oi_selection_object_;
> +}
> +
> +void lgsOiCreateBackground() {
> +  TRACE_ENTER();
> +  if ((oiCreationThread_.joinable() == true) || (stop_oi_create == true))
{
> +    // Thread is executing. Do nothing
> +    return;
> +  }
> +
> +  // Make sure that the OI is finalized before creating a new one
> +  // Note: oi_handle_ can be use unprotected here since we know that
there
> is
> +  // no running oiCreationThread
> +  finalizeOi(oi_handle_);
> +  oi_handle_ = 0;
> +  oi_selection_object_ = -1;
> +
> +  // Start a OI creation thread
> +  // Note: Throws an exception if "The system is unable to start a new
> thread"
> +  // Should never happen so it is not handled here (will cause node
restart)
> +  oiCreationThread_ = std::thread {&oiCreationThread};
> +}
> +
> +void lgsOiCreateSynchronous() {
> +  TRACE_ENTER();
> +  // Note: oi_handle_ can be use unprotected here since we know that
there
> is
> +  // no running oiCreationThread
> +  // There is no meaning to vall finalizeOI() since this function only
shall be
> +  // used for the first creation of an OI handle during initialization of
the
> +  // log service
> +  oi_handle_ = 0;
> +  oi_selection_object_ = -1;
> +
> +  SaAisErrorT ais_rc = createLogServerOi();
> +  LOG_NO("%s: createLogServerOi() %s", __FUNCTION__, saf_error(ais_rc));
> +}
> +
> +// Note: In this version this is just call lgsOiCreateBackground(). The
reason
> +// for having this function is to have a place where an implementer set
can
> +// be done instead of creating an OI if the lgsOiStop function is changed
> +// to just clear the OI. Note that if set fail the OI must be created
anyway
> +//
> +// This function shall be used only when changing HA state from standby
to
> +// active
> +void lgsOiStart() {
> +  TRACE_ENTER();
> +  lgsOiCreateBackground();
> +}
> +
> +// Note: oi_handle_ and oi_selection_object_ is always set in thread also
if
> +// thread is stopped. Is set to 0 and -1 respectively in all cases except
when
> +// an OI is successfully created
> +//
> +// Note: This version will completely finalize the OI. This is probably
good
> +//       enough. Clear / Set handling may be a bit faster but Stop /
Start of
> +//       OI should be rare.
> +//       If optimization is needed we can do implementer clear here
> +void lgsOiStop() {
> +  TRACE_ENTER();
> +  stop_oi_create = true;
> +
> +  // Handle thread if it exist
> +  if (oiCreationThread_.joinable() == true) {
> +    // Wait for thread to stop
> +    oiCreationThread_.join();
> +  }
> +
> +  // Note: oi_handle_ can be use unprotected here since we know that
there
> is
> +  // no running oiCreationThread
> +  finalizeOi(oi_handle_);
> +  oi_handle_ = 0;
> +  oi_selection_object_ = -1;
> +  stop_oi_create = false;
> +}
> diff --git a/src/log/logd/lgs_oi_admin.h b/src/log/logd/lgs_oi_admin.h
> new file mode 100644
> index 000000000..8502e30e7
> --- /dev/null
> +++ b/src/log/logd/lgs_oi_admin.h
> @@ -0,0 +1,105 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2008 The OpenSAF Foundation
> + * Copyright Ericsson AB 2008, 2018 - All Rights Reserved.
> + *
> + * 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 "ais/include/saImmOi.h"
> +
> +// Contains administrative handling of the lgs main object implementer
(OI)
> +// Implements functions for initializing an OI in a background thread,
> +// finalizing the OI and stop an ongoing initialization
> +// The reason for using a background thread is to not block the log
server.
> +// An initialize request may take up to 1 minute.
> +// When stopping the OI a running OI initializing thread is stopped and
the OI
> +// is finalized.
> +//
> +// Examples of situations when the functions are used:
> +// Starting log server: OI shall be intialized. This should be done in
> +//                      background so that start of log server is not
blocked.
> +//
> +// Switch/fail over:    The to become standby; must give up the OI. The
> chosen
> +//                      way of doing that is to finalize the OI. An
alternative
> +//                      is to only clear the OI which is no longer used
here.
> +//                      The to become active; must initialize an OI. An
> +//                      alternative is to keep the OI handle and just use
the
> +//                      set API
> +//
> +// BAD HANDLE:          IMM may return bad handle when synchronous
> operations
> +//                      are called including the dispatch function. If
this
> +//                      happen the OI shall be initialized again except
in a
> +//                      switch/fail over situation where the server shall
become
> +//                      standby
> +//
> +// Note1: The background thread puts a no-operation message in the
> mailbox
> +//        handled by the main poll loop when OI initialize is done. This
is
> +//        needed to handle installing of the IMM fd in the poll loop.
> +//
> +// Note2: The previous global immOiHandle and immSelectionObject
> variables in
> +//        cb struct are removed. Values can be fetched using thread safe
get
> +//        functions
> +
> +#ifndef LGS_OI_ADMIN_H
> +#define LGS_OI_ADMIN_H
> +
> +// Creates a new OI. Return false if fail.
> +// Note1: If there is an existing OI it will be deleted and a new is
created.
> +//        This means calling IMM finalize, setting oi_handle = 0,
> +//        oi_selection_object = -1 and starting the OI creation thread.
The
> +//        OI creation thread will update oi_handle and
oi_selection_object with
> +//        new values when creation is done.
> +//        Nothing will be done if OI creation is already ongoing when
this
> +//        function is called
> +// Note2: lgsOiCreateBackground() shall not be used when log server is
> starting.
> +//        During initialization configuration streams are created.
> +//        When creating a configuration stream cached Rt attributes has
to be
> +//        written and this requires a valid OI handle
> +//        Instead use lgsOiCreateSyncronous()
> +//
> +// This function shall also be used to restore the OI in case of a BAD
HANDLE
> +// return code when using the OI handle with an OI IMM operation.
> +void lgsOiCreateBackground();
> +
> +// Note3: This function shall only be called once and only when the log
> server
> +//        is initializing
> +// This function is not thread safe
> +void lgsOiCreateSynchronous();
> +
> +// Start an OI.
> +// Shall be used when this server shall become an OI.
> +// For example when becoming active
> +void lgsOiStart();
> +
> +// Stop an existing OI
> +// To be used when this server no longer shall be an OI.
> +// For example becoming standby
> +void lgsOiStop();
> +
> +// Get both OI handle and selection object. Guarantees that we get a pair
> +// that is created together. Return -1 if there is no selection object
and
> +// the value of out_oi_handle will be 0
> +// Is thread safe
> +SaSelectionObjectT lgsGetOiFdsParams(SaImmOiHandleT* out_oi_handle);
> +
> +// Returns the created OI selection object or -1 if there is none
> +// Is thread safe
> +SaSelectionObjectT lgsGetOiSelectionObject();
> +
> +// Returns the created OI handle or 0 if there is no handle
> +// Is thread safe
> +SaImmOiHandleT lgsGetOiHandle();
> +
> +#endif /* LGS_OI_ADMIN_H */
> +
> diff --git a/src/log/logd/lgs_recov.cc b/src/log/logd/lgs_recov.cc
> index dcaad188d..7c0197b7f 100644
> --- a/src/log/logd/lgs_recov.cc
> +++ b/src/log/logd/lgs_recov.cc
> @@ -15,9 +15,11 @@
>   *
>   */
> 
> -#include "lgs_recov.h"
> +#include "log/logd/lgs_recov.h"
> +
>  #include "log/logd/lgs_file.h"
>  #include "log/logd/lgs_filehdl.h"
> +#include "log/logd/lgs_imm.h"
> 
>  /***
>   * The following functions are used to handle a list of runtime stream
objects
> diff --git a/src/log/logd/lgs_stream.cc b/src/log/logd/lgs_stream.cc
> index 0c83e305b..4f50f5a98 100644
> --- a/src/log/logd/lgs_stream.cc
> +++ b/src/log/logd/lgs_stream.cc
> @@ -30,14 +30,16 @@
>  #include "log/logd/lgs_stream.h"
>  #include <algorithm>
> 
> +#include "base/osaf_time.h"
> +#include "osaf/immutil/immutil.h"
> +
>  #include "log/logd/lgs.h"
>  #include "log/logd/lgs_config.h"
>  #include "log/logd/lgs_file.h"
>  #include "log/logd/lgs_filehdl.h"
>  #include "log/logd/lgs_mbcsv_v1.h"
>  #include "log/logd/lgs_mbcsv_v2.h"
> -#include "base/osaf_time.h"
> -#include "osaf/immutil/immutil.h"
> +#include "log/logd/lgs_oi_admin.h"
> 
>  #define DEFAULT_NUM_APP_LOG_STREAMS 64
> 
> @@ -444,15 +446,18 @@ void log_stream_delete(log_stream_t **s) {
> 
>    if (lgs_cb->ha_state == SA_AMF_HA_ACTIVE) {
>      if (stream->isRtStream == SA_TRUE) {
> -      SaAisErrorT rv;
> +      SaAisErrorT ais_rc;
>        TRACE("Stream is closed, I am HA active so remove IMM object");
>        SaNameT objectName;
>        osaf_extended_name_lend(stream->name.c_str(), &objectName);
> -      rv = saImmOiRtObjectDelete(lgs_cb->immOiHandle, &objectName);
> -      if (rv != SA_AIS_OK) {
> +      ais_rc = saImmOiRtObjectDelete(lgsGetOiHandle(), &objectName);
> +      if (ais_rc != SA_AIS_OK) {
> +        if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
> +          lgsOiCreateBackground();
> +        }
>          /* no retry; avoid blocking LOG service #1886 */
> -        LOG_WA("saImmOiRtObjectDelete returned %u for %s", rv,
> -               stream->name.c_str());
> +        LOG_WA("%s: saImmOiRtObjectDelete returned %s for %s",
> +               __FUNCTION__, saf_error(ais_rc), stream->name.c_str());
>        }
>      }
>    }
> @@ -514,6 +519,53 @@ int lgs_populate_log_stream(
>    return rc;
>  }
> 
> +// Wrap creation of a runtime object. Handle try again ERR_EXIST
> +// If the object already exist it is deleted and then the new object is
created
> +// Note: This is a help function to be used in createRtObject() only
> +// Note: immutil is used
> +// The first 4 parameters are the same as for
> immutil_saImmOiRtObjectCreate_2
> +// The last parameter is the same as object name used with
> +// immutil_saImmOiRtObjectDelete()
> +static SaAisErrorT createRtObject(const SaImmOiHandleT oi_handle,
> +                                  const SaImmClassNameT class_name,
> +                                  const SaNameT* parent_name,
> +                                  const SaImmAttrValuesT_2**
attribute_values,
> +                                  const SaNameT *object_name) {
> +SaAisErrorT ais_rc = SA_AIS_OK;
> +
> +  for (int i = 0; i <= 2; i++) {
> +    ais_rc = immutil_saImmOiRtObjectCreate_2(oi_handle,
> +                                             class_name,
> +                                             parent_name,
> +                                             attribute_values);
> +    if (ais_rc == SA_AIS_ERR_EXIST) {
> +      SaAisErrorT del_rc = immutil_saImmOiRtObjectDelete(oi_handle,
> object_name);
> +      if (del_rc == SA_AIS_ERR_BAD_HANDLE) {
> +        LOG_NO("%s: saImmOiRtObjectDelete() Fail, %s", __FUNCTION__,
> +               saf_error(del_rc));
> +        lgsOiCreateBackground();
> +      } else if (del_rc != SA_AIS_OK) {
> +        LOG_NO("%s: saImmOiRtObjectDelete() Fail, %s", __FUNCTION__,
> +               saf_error(del_rc));
> +        break;
> +      } else {
> +        // The existing object is deleted. Try again to create a new one
> +        continue;
> +      }
> +    } else if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
> +      LOG_NO("%s: saImmOiRtObjectCreate_2() Fail, %s",
> +             __FUNCTION__, saf_error(ais_rc));
> +      lgsOiCreateBackground();
> +      break;
> +    } else {
> +      break;
> +    }
> +  }
> +
> +  // saImmOiRtObjectCreate_2() return code
> +  return ais_rc;
> +}
> +
>  /**
>   * Create a new rt app stream object.
>   *
> @@ -536,8 +588,9 @@ SaAisErrorT
> lgs_create_appstream_rt_object(log_stream_t *const stream) {
>        parent_name++; /* FIX, vulnerable for malformed DNs */
>        parentName = &parent;
>        osaf_extended_name_lend(parent_name, &parent);
> -    } else
> +    } else {
>        rdnstr = const_cast<char *>(stream->name.c_str());
> +    }
> 
>      void *arr1[] = {&rdnstr};
>      const SaImmAttrValuesT_2 attr_safLgStr = {
> @@ -622,14 +675,20 @@ SaAisErrorT
> lgs_create_appstream_rt_object(log_stream_t *const stream) {
>          &attr_saLogStreamCreationTimestamp,
>          NULL};
> 
> -    rc = immutil_saImmOiRtObjectCreate_2(
> -        lgs_cb->immOiHandle,
> const_cast<SaImmClassNameT>("SaLogStream"),
> -        parentName, attrValues);
> +    SaNameT object_name;
> +    osaf_extended_name_lend(stream->name.c_str(), &object_name);
> +    SaImmOiHandleT oi_handle = lgsGetOiHandle();
> +    rc = createRtObject(oi_handle,
> +                        const_cast<SaImmClassNameT>("SaLogStream"),
> +                        parentName,
> +                        attrValues,
> +                        &object_name);
>      free(dndup);
> 
>      if (rc != SA_AIS_OK) {
> -      LOG_WA("saImmOiRtObjectCreate_2 returned %u for %s, parent %s", rc,
> -             stream->name.c_str(), parent_name);
> +      LOG_WA("%s: createRtObject() returned %s for %s, "
> +             "parent %s", __FUNCTION__, saf_error(rc),
stream->name.c_str(),
> +             parent_name);
>      }
>    }
> 
> --
> 2.16.2



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to