When multiple requests modify the same counter concurrently, read-increment-write patterns produce incorrect results. An atomic counter solves this by incrementing or decrementing a column value in a single, isolated server-side operation. Use it for concurrent-write counters where accuracy matters--for example, tracking page views, vote counts, or inventory quantities.
Tablestore SDK for Python V5.1.0 or later supports the atomic counter feature.
Prerequisites
-
An OTSClient instance is initialized. For more information, see Initialize an OTSClient instance.
-
A data table is created and data is written to the data table.
Usage notes
-
You can implement atomic counters only on INTEGER columns.
-
If a column that is specified as an atomic counter does not exist before you write data, the default value of the column is 0. If a column that is specified as an atomic counter is not an INTEGER column, an OTSParameterInvalid error occurs.
-
You can update an atomic counter by using a positive or negative number, but you must avoid an integer overflow. If an integer overflow occurs, an OTSParameterInvalid error is returned.
-
By default, the value of an atomic counter is not returned in the response to an update row request. You can specify that the updated value of an atomic counter is returned.
-
You cannot specify a column as an atomic counter and update the column in a single update request. For example, if you set Column A to an atomic counter, you cannot perform other operations such as overwrite and delete operations on the column at the same time.
-
You can perform multiple update operations on the same row by sending a BatchWriteRow request. However, if you perform an atomic counter operation on a row, you can perform only one update operation on the row in a BatchWriteRow request.
-
Only the value of the latest version of an atomic counter can be updated. You cannot update the value of a specified version of an atomic counter. After an update operation is complete, a new version of data is inserted into the atomic counter in the row.
When to use
An atomic counter is appropriate when slight overcounting or undercounting is acceptable. For example, you might track page views and increment the counter on each visit. If a retry increments the counter twice, the slight discrepancy is tolerable.
An atomic counter is not appropriate when every count must be exact--for example, in financial ledgers or banking transactions. In these cases, use a conditional update instead. Conditional updates verify the current value before applying a change, ensuring correctness at the cost of lower throughput under contention.
Common use cases:
Page view counters and visitor statistics
Vote tallies and like counts
Inventory quantities where exact precision is not critical
The atomic counter is exposed through the updateRow operation as the following update type:
|
Operation |
Description |
|
|
Increases or decreases the value of an |
How it works
Tablestore applies the delta atomically on the server side, so concurrent requests produce correct cumulative results without the read-check-write race condition.
Each updateRow call with INCREMENT is not idempotent: repeating the same request increments the counter again. A positive delta causes overcounting; a negative delta causes undercounting. If your application retries failed requests, use a conditional update with a version check to skip duplicate increments.
The following table describes the parameters:
|
Parameter |
Description |
|
|
The name of the data table. |
|
|
The name of the column to increment or decrement. The column must be of the |
|
|
The amount to add or subtract. Use a positive integer to increment and a negative integer to decrement. |
Examples
The following example increments the price column by 6:
Before the update: The row has price set to 10.
After the update: The price column becomes 16.
def increment_by_update_row(client):
# Specify the name of the data table.
table_name = '<TABLE_NAME>'
primary_key = [('pk0', 1)]
# Use INCREMENT to increase the price column by 6.
update_of_attribute_columns = {
'INCREMENT': [('price', 6)]
}
row = Row(primary_key, update_of_attribute_columns)
consumed, return_row = client.update_row(table_name, row, None)
print('Update succeeded, consumed %s write capacity units.' % consumed.write)