32
32
#include < lib/support/CHIPCounter.h>
33
33
#include < lib/support/CodeUtils.h>
34
34
#include < lib/support/DefaultStorageKeyAllocator.h>
35
+ #include < limits>
35
36
36
37
namespace chip {
37
38
@@ -104,16 +105,50 @@ class PersistedCounter : public MonotonicallyIncreasingCounter<T>
104
105
}
105
106
#endif
106
107
107
- ReturnErrorOnFailure (PersistNextEpochStart (startValue + aEpoch));
108
+ ReturnErrorOnFailure (PersistNextEpochStart (static_cast <T>( startValue + aEpoch) ));
108
109
109
110
// This will set the starting value, after which we're ready.
110
111
return MonotonicallyIncreasingCounter<T>::Init (startValue);
111
112
}
112
113
113
114
/* *
114
- * @brief
115
- * Increment the counter and write to persisted storage if we've completed
116
- * the current epoch.
115
+ * @brief Increment the counter by N and write to persisted storage if we've completed the current epoch.
116
+ *
117
+ * @param value value of N
118
+ *
119
+ * @return Any error returned by a write to persisted storage.
120
+ */
121
+ CHIP_ERROR AdvanceBy (T value) override
122
+ {
123
+ VerifyOrReturnError (mStorage != nullptr , CHIP_ERROR_INCORRECT_STATE);
124
+ VerifyOrReturnError (mKey .IsInitialized (), CHIP_ERROR_INCORRECT_STATE);
125
+
126
+ // If value is 0, we do not need to do anything
127
+ VerifyOrReturnError (value > 0 , CHIP_NO_ERROR);
128
+
129
+ // We should update the persisted epoch value if :
130
+ // 1- Sum of the current counter and value is greater or equal to the mNextEpoch.
131
+ // This is the standard operating case.
132
+ // 2- Increasing the current counter by value would cause a roll over. This would cause the current value to be < to the
133
+ // mNextEpoch so we force an update.
134
+ bool shouldDoEpochUpdate = ((MonotonicallyIncreasingCounter<T>::GetValue () + value) >= mNextEpoch ) ||
135
+ (MonotonicallyIncreasingCounter<T>::GetValue () > std::numeric_limits<T>::max () - value);
136
+
137
+ ReturnErrorOnFailure (MonotonicallyIncreasingCounter<T>::AdvanceBy (value));
138
+
139
+ if (shouldDoEpochUpdate)
140
+ {
141
+ // Since AdvanceBy allows the counter to be increased by an arbitrary value, it is possible that the new counter value
142
+ // is greater than mNextEpoch + mEpoch. As such, we want the next Epoch value to be calculated from the new current
143
+ // value.
144
+ PersistAndVerifyNextEpochStart (MonotonicallyIncreasingCounter<T>::GetValue ());
145
+ }
146
+
147
+ return CHIP_NO_ERROR;
148
+ }
149
+
150
+ /* *
151
+ * @brief Increment the counter and write to persisted storage if we've completed the current epoch.
117
152
*
118
153
* @return Any error returned by a write to persisted storage.
119
154
*/
@@ -126,18 +161,32 @@ class PersistedCounter : public MonotonicallyIncreasingCounter<T>
126
161
127
162
if (MonotonicallyIncreasingCounter<T>::GetValue () >= mNextEpoch )
128
163
{
129
- // Value advanced past the previously persisted "start point".
130
- // Ensure that a new starting point is persisted.
131
- ReturnErrorOnFailure (PersistNextEpochStart (mNextEpoch + mEpoch ));
132
-
133
- // Advancing the epoch should have ensured that the current value
134
- // is valid
135
- VerifyOrReturnError (MonotonicallyIncreasingCounter<T>::GetValue () < mNextEpoch , CHIP_ERROR_INTERNAL);
164
+ ReturnErrorOnFailure (PersistAndVerifyNextEpochStart (mNextEpoch ));
136
165
}
166
+
137
167
return CHIP_NO_ERROR;
138
168
}
139
169
140
170
private:
171
+ CHIP_ERROR PersistAndVerifyNextEpochStart (T refEpoch)
172
+ {
173
+ // Value advanced past the previously persisted "start point".
174
+ // Ensure that a new starting point is persisted.
175
+ ReturnErrorOnFailure (PersistNextEpochStart (static_cast <T>(refEpoch + mEpoch )));
176
+
177
+ // Advancing the epoch should have ensured that the current value is valid
178
+ VerifyOrReturnError (static_cast <T>(MonotonicallyIncreasingCounter<T>::GetValue () + mEpoch ) == mNextEpoch ,
179
+ CHIP_ERROR_INTERNAL);
180
+
181
+ // Previous check did not take into consideration that the counter value can be equal to the max counter value or
182
+ // rollover.
183
+ // TODO(#33175): PersistedCounter allows rollover so this check is incorrect. We need a Counter class that adequatly
184
+ // manages rollover behavior for counters that cannot rollover.
185
+ // VerifyOrReturnError(MonotonicallyIncreasingCounter<T>::GetValue() < mNextEpoch, CHIP_ERROR_INTERNAL);
186
+
187
+ return CHIP_NO_ERROR;
188
+ }
189
+
141
190
/* *
142
191
* @brief
143
192
* Write out the counter value to persistent storage.
@@ -146,7 +195,8 @@ class PersistedCounter : public MonotonicallyIncreasingCounter<T>
146
195
*
147
196
* @return Any error returned by a write to persistent storage.
148
197
*/
149
- CHIP_ERROR PersistNextEpochStart (T aStartValue)
198
+ CHIP_ERROR
199
+ PersistNextEpochStart (T aStartValue)
150
200
{
151
201
mNextEpoch = aStartValue;
152
202
#if CHIP_CONFIG_PERSISTED_COUNTER_DEBUG_LOGGING
0 commit comments