Optimistic Lock of TcaplusDB
TcaplusDB maintains a version number for each data entry to ensure the consistency of multiple clients' access to the same data. Each time the data is changed, the version number will increase automatically, and the version number will not change when the data is read.
When submitting an update request, users can specify the expected data version number. The update will only be performed when the current data version number is consistent with the expected version number. Otherwise, the update will fail and the error (error code: -7949 (SVR_ERR_FAIL_INVALID_VERSION)) will be returned to users. If receiving an error indicating that the version number is expired, users should obtain the latest data version number, use the obtained version number as the new expected data version number, and resend the update request until the update is successful or other conditions (for example, the number of retries or retry time reaches the upper limit) are met.
Note: When the data version number exceeds the upper limit of int32, it will overflow and reverse, and the optimistic lock will become invalid. After overflow, it becomes 0. 0 means that the optimistic lock is not enabled, and it becomes 1 when it is updated again. The following is the normal optimistic lock mechanism.
1. Application Scenarios
It can support multiple clients to modify the same piece of data and ensure the consistency of data access. That is, after the client reads the data, it should ensure that no other client modifies the data during the modification period.
It is applicable to scenarios with low writing conflict probability. If the writing conflict probability is high, the overall performance may be degraded due to repeated retries. At this time, the app may need to consider other better solutions (such as pessimistic locks).
2. Instructions
Taking the TDR Table C++SDK as an example, the two main interface functions involved in optimistic lock are GetVersion and SetVersion. The function descriptions are as follows:
GetVersion
/**
@brief: get the record version number
@retval: record version number
@note: For the Generic operation, it means getting the version of the Record; whereas for the List operation, it means getting the version of the List in which the Record is located.
*/
int32_t GetVersion() const;
SetVersion
/**
@brief: set the version number of the record
@param [IN] iVersion: version number of the record <=0: it means that the version number is not important. The specific meaning is as follows.
When the value of the parameter type passed into the int SetCheckDataVersionPolicy(enum tagCHECKDATAVERSIONTYPE type) function of class TcaplusServiceRequest is CHECKDATAVERSION_AUTOINCREASE: it means that the record version number is to be checked. If the value of the parameter iVersion passed into the void SetVersion (IN int32_t iVersion) function of class TcaplusServiceRecord is <= 0, it still means that the version number is not important; if the value of the parameter iVersion passed into the void SetVersion (IN int32_t iVersion) function of class TcaplusServiceRecord is > 0, the Replace, Update, Increase, ListAddAfter, ListDelete, ListReplace, and ListDeleteBatch operations will succeed only if the version number is the same as the server side version number. And the version number will increase by 1 on the server side.
When the value of the parameter type passed into the int SetCheckDataVersionPolicy(enum tagCHECKDATAVERSIONTYPE type) function of the class TcaplusServiceRequest is NOCHECKDATAVERSION_OVERWRITE: it means that the record version number is not checked. If the value of the parameter iVersion passed into the void SetVersion (IN int32_t iVersion) function of class TcaplusServiceRecord is <= 0, the version number 1 will be written to the record version number on the server side (the record version number successfully written on the server side is at least 1); if the value of the parameter iVersion passed into the void SetVersion (IN int32_t iVersion) function of class TcaplusServiceRecord is > 0, the version number will be written to the record version number on the server side.
When the value of the parameter type passed into the int SetCheckDataVersionPolicy(enum tagCHECKDATAVERSIONTYPE type) function of class TcaplusServiceRequest is NOCHECKDATAVERSION_AUTOINCREASE: It means that the record version number is not checked, and the version number on the server side will increase by 1. If the server side newly writes a data record, the newly written data record version number is 1.
@retval void
*/
//Attention: For the Generic operation, it means setting the version of the Record, whereas for the List operation, it means setting the version of the List unit in which the Record is located.
void SetVersion(IN int32_t iVersion);
From the perspective of a single client, the data update process based on optimistic locks mainly involves the following steps:
Query the data to be modified, and obtain the current data version number through the GetVersion function of the Record. There is no need to set the expected version of the data by SetVersion;
Construct the data update request, set the expected data version number through the SetVersion function of the Record in the request, and send the request;
Check the response to the update request. If a -7949 (SVR_ERR_FAIL_INVALID_VERSION) error is returned, it indicates that data has been updated by another client between Step 1 and Step 2. At this time, you need to retry the whole process from step 1. If the returned modification is successful, the process ends.
Steps for updating PB table optimistic lock data:
Query the data to be modified and obtain the current version number of the data through the GetMessage Option function of the record object;
Construct a data update request and set the expected data version number, i.e. the version number obtained in step 1, through the SetMessage Option function of the record object in the request, and send the request;
Check the response to the update request. If an error code of -7949 (SVR-ERR-FAIL_INVALId_VERSION) is returned, it indicates that another client has updated data between step 1 and step 2. At this point, the entire process needs to be retried starting from step 1. If the modification returned is successful, the process will be terminated directly. Note: If the app does not need version verification when updating data, you can call SetVersion and set it to - 1 or 0.