diff --git a/include/rbus.h b/include/rbus.h index 85250659..176f5a89 100644 --- a/include/rbus.h +++ b/include/rbus.h @@ -1121,6 +1121,44 @@ rbusError_t rbus_setMulti( rbusProperty_t properties, rbusSetOptions_t* opts); +/** @fn rbusError_t rbus_setMultiExt( + * rbusHandle_t handle, + * int numProps, + * rbusProperty_t properties, + * rbusSetOptions_t* opts, + * uint8_t timeout, + * char** failedParameterName); + * + * @brief A component uses this to perform a set operation for multiple parameters at once. + * This method identifies the provider component of each parameter, groups them and makes the SET call \n + * per provider component. The given order is NOT maintained. + * + * This API ensures rolling back of all the property to previous value upon failure to set any single parameter in the given list. + * Used by: All components that need to set multiple parameters + * + * @param handle Bus Handle + * @param numProps The number (count) of parameters + * @param properties The list of dml properties to set to. + * For each parameter, a property should be created which contains the parameter's name and + * the respective value to set that parameter to. + * @param opts Extra options such as session info. + * Set NULL if not needed, in which case a session + * is not used and the set is commited immediately. + * @param timeout Timeout to be used for each SET per provider; Set to 0 to use the default value (15s). + * @param failedParameterName Output parameter that represents the failed property. On success, it will returning NULL. Caller responsible to free() this. + * @return RBus error code as defined by rbusError_t. + * Possible values are: + * RBUS_ERROR_INVALID_INPUT: Given inputs are not correct. + * RBUS_ERROR_ACCESS_NOT_ALLOWED: Access to requested parameter is not permitted. + * RBUS_ERROR_DESTINATION_NOT_REACHABLE: Destination element was not reachable. + */ +rbusError_t rbus_setMultiExt( + rbusHandle_t handle, + int numProps, + rbusProperty_t properties, + rbusSetOptions_t* opts, + uint8_t timeout, + char** failedParameterName); /** @fn rbusError_t rbus_setBoolean( * rbusHandle_t handle, diff --git a/include/rbus_property.h b/include/rbus_property.h index 4ba5cb32..e5ce08d0 100644 --- a/include/rbus_property.h +++ b/include/rbus_property.h @@ -302,12 +302,12 @@ void rbusProperty_Append(rbusProperty_t property, rbusProperty_t back); #define rbusProperty_PushBack(prop, back) rbusProperty_Append((prop),(back)) -/** @fn void rbusProperty_Count(rbusProperty_t property) +/** @fn int rbusProperty_Count(rbusProperty_t property) * @brief Return the number or properties in the list * @param property A property (the first in list). * @return The number of properties in the list. */ -uint32_t rbusProperty_Count(rbusProperty_t property); +int rbusProperty_Count(rbusProperty_t property); void rbusProperty_fwrite(rbusProperty_t prop, int depth, FILE* fout); diff --git a/src/rbus/rbus.c b/src/rbus/rbus.c index 1c575af4..d1e61157 100644 --- a/src/rbus/rbus.c +++ b/src/rbus/rbus.c @@ -1419,9 +1419,11 @@ static int _master_event_callback_handler(char const* sender, char const* eventN static void _set_callback_handler (rbusHandle_t handle, rbusMessage request, rbusMessage *response) { rbusError_t rc = 0; + rbusError_t err = 0; int sessionId = 0; int numVals = 0; int loopCnt = 0; + int rollBack = 0; char* pCompName = NULL; char* pIsCommit = NULL; bool isCommit = false; @@ -1429,13 +1431,16 @@ static void _set_callback_handler (rbusHandle_t handle, rbusMessage request, rbu rbusProperty_t* pProperties = NULL; struct _rbusHandle* handleInfo = (struct _rbusHandle*)handle; rbusSetHandlerOptions_t opts; + rbusProperty_t cachedData = NULL; memset(&opts, 0, sizeof(opts)); + rbusGetHandlerOptions_t options; + memset(&options, 0, sizeof(rbusGetHandlerOptions_t)); rbusMessage_GetInt32(request, &sessionId); rbusMessage_GetString(request, (char const**) &pCompName); + rbusMessage_GetInt32(request, &rollBack); rbusMessage_GetInt32(request, &numVals); - if(numVals > 0) { /* Update the Get Handler input options */ @@ -1470,8 +1475,21 @@ static void _set_callback_handler (rbusHandle_t handle, rbusMessage request, rbu el = retrieveInstanceElementEx(handle, handleInfo->elementRoot, paramName, true); if(el != NULL) { + rbusProperty_t currentData = NULL; if(el->cbTable.setHandler) { + if(rollBack == 1) + { + if(el->cbTable.getHandler) + { + rbusProperty_Init(¤tData, paramName, NULL); + ELM_PRIVATE_LOCK(el); + rc = el->cbTable.getHandler(handle, currentData, &options); + ELM_PRIVATE_UNLOCK(el); + } + else + RBUSLOG_INFO("%s is a write only parameter",paramName); + } if(isCommit && loopCnt == numVals -1) opts.commit = true; @@ -1482,11 +1500,42 @@ static void _set_callback_handler (rbusHandle_t handle, rbusMessage request, rbu { RBUSLOG_WARN("Set Failed for %s; Component Owner returned Error", paramName); pFailedElement = paramName; + if(rollBack == 1) + { + RBUSLOG_DEBUG("Reverting because set failed for this param:%s",pFailedElement); + /*===========< Rollback old values >============*/ + rbusProperty_t prevProp = cachedData; + while(prevProp) + { + char const* prevParamName = rbusProperty_GetName(prevProp); + el = retrieveInstanceElement(handleInfo->elementRoot, prevParamName); + ELM_PRIVATE_LOCK(el); + err = el->cbTable.setHandler(handle, prevProp, &opts); + ELM_PRIVATE_UNLOCK(el); + prevProp = rbusProperty_GetNext(prevProp); + if(err != RBUS_ERROR_SUCCESS) + { + RBUSLOG_WARN("Reverting paramValues of %s to initial values failed",prevParamName); + } + } + } break; } else { setPropertyChangeComponent(el, pCompName); + /* ======== < Old values backup >============= */ + if (currentData) + { + if (cachedData == NULL) + cachedData = currentData; + else + { + rbusProperty_Append(cachedData, currentData); + rbusProperty_Release(currentData); + } + } + } } else @@ -1523,7 +1572,12 @@ static void _set_callback_handler (rbusHandle_t handle, rbusMessage request, rbu exit: rbusMessage_Init(response); rbusMessage_SetInt32(*response, (int) rc); - if (pFailedElement) + if (rc == RBUS_ERROR_SUCCESS) + { + rbusPropertyList_appendToMessage(cachedData, *response); + rbusProperty_Release(cachedData); + } + else if(pFailedElement) rbusMessage_SetString(*response, pFailedElement); if(pProperties) @@ -3835,6 +3889,7 @@ rbusError_t rbus_set(rbusHandle_t handle, char const* name,rbusValue_t value, rb /* Set the Component name that invokes the set */ rbusMessage_SetString(setRequest, handleInfo->componentName); + rbusMessage_SetInt32(setRequest, 0);//needRollBack /* Set the Size of params */ rbusMessage_SetInt32(setRequest, 1); @@ -3950,20 +4005,25 @@ rbusError_t rbus_setCommit(rbusHandle_t handle, char const* name, rbusSetOptions return errorcode; } -rbusError_t rbus_setMulti(rbusHandle_t handle, int numProps, rbusProperty_t properties, rbusSetOptions_t* opts) +rbusError_t _setMultiInternal(rbusHandle_t handle, int numProps, rbusProperty_t properties, rbusSetOptions_t* opts, uint8_t timeout, char** pFailedElement, bool rollBack) { rbusError_t errorcode = RBUS_ERROR_INVALID_INPUT; rbusCoreError_t err = RBUSCORE_SUCCESS; - VERIFY_HANDLE(handle); + VERIFY_HANDLE(handle); rbusMessage setRequest, setResponse; struct _rbusHandle* handleInfo = (struct _rbusHandle*) handle; rbusValueType_t type = RBUS_NONE; rbusProperty_t current; - + int cachedNumProps = 0; + rbusProperty_t cachedProperties = NULL; VERIFY_NULL(handle); + if(timeout == 0) + timeout = rbusConfig_ReadSetTimeout(); if (handleInfo->m_handleType != RBUS_HWDL_TYPE_REGULAR) + { return RBUS_ERROR_INVALID_HANDLE; + } if (numProps > 0 && properties != NULL) { @@ -4032,7 +4092,6 @@ rbusError_t rbus_setMulti(rbusHandle_t handle, int numProps, rbusProperty_t prop char* componentName = NULL; char const* firstParamName = NULL; int batchCount = 0; - for(i = 0; i < numProps; ++i) { if(componentNames[i]) @@ -4053,7 +4112,6 @@ rbusError_t rbus_setMulti(rbusHandle_t handle, int numProps, rbusProperty_t prop if(componentName) { - rbusMessage_Init(&setRequest); /* Set the Session ID first */ @@ -4064,6 +4122,10 @@ rbusError_t rbus_setMulti(rbusHandle_t handle, int numProps, rbusProperty_t prop /* Set the Component name that invokes the set */ rbusMessage_SetString(setRequest, handleInfo->componentName); + if(rollBack) + rbusMessage_SetInt32(setRequest, 1); + else + rbusMessage_SetInt32(setRequest, 0); /* Set the Size of params */ rbusMessage_SetInt32(setRequest, batchCount); @@ -4082,40 +4144,62 @@ rbusError_t rbus_setMulti(rbusHandle_t handle, int numProps, rbusProperty_t prop free(componentNames[i]); componentNames[i] = NULL; } - } + } /* Set the Commit value; FIXME: Should we use string? */ rbusMessage_SetString(setRequest, (!opts || opts->commit) ? "TRUE" : "FALSE"); - - if((err = rbus_invokeRemoteMethod(firstParamName, METHOD_SETPARAMETERVALUES, setRequest, rbusConfig_ReadSetTimeout(), &setResponse)) != RBUSCORE_SUCCESS) + if((err = rbus_invokeRemoteMethod(firstParamName, METHOD_SETPARAMETERVALUES, setRequest, (int)timeout, &setResponse)) != RBUSCORE_SUCCESS) { RBUSLOG_ERROR("set by %s failed; Received error %d from RBUS Daemon for the object %s", handle->componentName, err, firstParamName); errorcode = rbusCoreError_to_rbusError(err); } else { - char const* pErrorReason = NULL; rbusLegacyReturn_t legacyRetCode = RBUS_LEGACY_ERR_FAILURE; int ret = -1; rbusMessage_GetInt32(setResponse, &ret); - RBUSLOG_DEBUG("Response from the remote method is [%d]!", ret); errorcode = (rbusError_t) ret; legacyRetCode = (rbusLegacyReturn_t) ret; - if((errorcode == RBUS_ERROR_SUCCESS) || (legacyRetCode == RBUS_LEGACY_ERR_SUCCESS)) { errorcode = RBUS_ERROR_SUCCESS; RBUSLOG_DEBUG("Successfully Set the Value"); + rbusPropertyList_initFromMessage(&cachedProperties, setResponse); + pFailedElement = NULL; } else { - rbusMessage_GetString(setResponse, &pErrorReason); - RBUSLOG_WARN("Failed to Set the Value for %s", pErrorReason); + rbusMessage_GetString(setResponse, (char const**)pFailedElement); + RBUSLOG_WARN("Failed to Set the Value for %s", *pFailedElement); + if(rollBack) + { + char *pTempFailedElement = NULL; + rbusSetOptions_t revertOpts; + if ((opts) && (opts->sessionId != 0)) + { + revertOpts.commit = true; + revertOpts.sessionId= opts->sessionId; + } + else + { + revertOpts.commit = true; + revertOpts.sessionId = 0; + } + cachedNumProps = 0; + cachedNumProps = rbusProperty_Count(cachedProperties); + rbusError_t result; + result = _setMultiInternal(handle, cachedNumProps, cachedProperties, &revertOpts, (int)timeout, &pTempFailedElement, false); + if(result == RBUS_ERROR_SUCCESS) + RBUSLOG_WARN("Successfully reverted back the values"); + else if((result != RBUS_ERROR_SUCCESS) && (pTempFailedElement)) + RBUSLOG_WARN("Failed to rollback %s\n",pTempFailedElement); + } if(legacyRetCode > RBUS_LEGACY_ERR_SUCCESS) { errorcode = CCSPError_to_rbusError(legacyRetCode); } + break; } /* Release the reponse message */ @@ -4147,9 +4231,21 @@ rbusError_t rbus_setMulti(rbusHandle_t handle, int numProps, rbusProperty_t prop if(componentNames) free(componentNames); } + if(cachedProperties) + free(cachedProperties); return errorcode; } +rbusError_t rbus_setMulti(rbusHandle_t handle, int numProps, rbusProperty_t properties, rbusSetOptions_t* opts) +{ + return _setMultiInternal(handle, numProps, properties, opts, 0, NULL, true); +} + +rbusError_t rbus_setMultiExt(rbusHandle_t handle, int numProps, rbusProperty_t properties, rbusSetOptions_t* opts, uint8_t timeout, char** failedParameterName) +{ + return _setMultiInternal(handle, numProps, properties, opts, timeout, failedParameterName, true); +} + static rbusError_t rbus_setByType(rbusHandle_t handle, char const* paramName, void const* paramVal, rbusValueType_t type) { rbusError_t errorcode = RBUS_ERROR_INVALID_INPUT; diff --git a/src/rbus/rbus_property.c b/src/rbus/rbus_property.c index 368de221..a8a50618 100644 --- a/src/rbus/rbus_property.c +++ b/src/rbus/rbus_property.c @@ -201,9 +201,9 @@ void rbusProperty_Append(rbusProperty_t property, rbusProperty_t back) rbusProperty_SetNext(last, back); } -uint32_t rbusProperty_Count(rbusProperty_t property) +int rbusProperty_Count(rbusProperty_t property) { - uint32_t count = 1; + int count = 1; rbusProperty_t prop = property; if(!prop) return 0;