Skip to content

Commit 242220a

Browse files
authored
Bug 2038991 - Update Cache when calling register_previous_gecko_pref_states (#7369)
Bug 2021137 removed end_initialize and set `writer.commit()` to prevent a loop. However, this change had a side-effect of a stale cache. This patch fixes it by: * Adding a param of `update_gecko_prefs` to `commit_and_update` * Having `register_previous_gecko_pref_states` call `commit_and_update` with `update_gecko_prefs=false` * Updating `map_gecko_prefs_to_enrollment_slugs_and_update_store` to take a param of `update_gecko_prefs`, when false, it will not set information with Gecko
1 parent 1b1ea75 commit 242220a

6 files changed

Lines changed: 65 additions & 15 deletions

File tree

components/nimbus/src/stateful/dbcache.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,21 @@ impl DatabaseCache {
4343
//
4444
// This function must be passed a `&Database` and a `Writer`, which it
4545
// will commit before updating the in-memory cache. This is a slightly weird
46-
// API but it helps encorce two important properties:
46+
// API but it helps enforce two important properties:
4747
//
4848
// * By requiring a `Writer`, we ensure mutual exclusion of other db writers
4949
// and thus prevent the possibility of caching stale data.
5050
// * By taking ownership of the `Writer`, we ensure that the calling code
5151
// updates the cache after all of its writes have been performed.
52+
// * `update_gecko_prefs` - Pass true for regular enrollment changes. Pass false
53+
// when the Gecko prefs do not need to be synced with Gecko.
5254
pub fn commit_and_update(
5355
&self,
5456
db: &Database,
5557
writer: Writer,
5658
coenrolling_ids: &HashSet<&str>,
5759
gecko_pref_store: Option<Arc<GeckoPrefStore>>,
60+
update_gecko_prefs: bool,
5861
) -> Result<()> {
5962
// By passing in the active `writer` we read the state of enrollments
6063
// as written by the calling code, before it's committed to the db.
@@ -80,6 +83,7 @@ impl DatabaseCache {
8083
&experiments,
8184
&enrollments,
8285
&experiments_by_slug,
86+
update_gecko_prefs,
8387
)
8488
});
8589

components/nimbus/src/stateful/gecko_prefs.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ impl GeckoPrefStore {
221221
enrollments: &[ExperimentEnrollment],
222222
// contains slug of enrolled branch
223223
experiments_by_slug: &HashMap<String, EnrolledExperiment>,
224+
// when true, sets Gecko prefs using the handler. when false, only updates internal store state
225+
update_gecko_prefs: bool,
224226
) -> HashMap<String, HashSet<String>> {
225227
struct RecipeData<'a> {
226228
experiment: &'a Experiment,
@@ -325,17 +327,20 @@ impl GeckoPrefStore {
325327
}
326328
}
327329

328-
// obtain a list of all Gecko pref states for which there is an enrollment value
329-
let mut set_state_list = Vec::new();
330-
state.gecko_prefs_with_state.iter().for_each(|(_, props)| {
331-
props.iter().for_each(|(_, pref_state)| {
332-
if pref_state.enrollment_value.is_some() {
333-
set_state_list.push(pref_state.clone());
334-
}
330+
// setting with Gecko is used for true updates, sometimes the state just needs to be recalculated (e.g., registering the original value on the enrollment)
331+
if update_gecko_prefs {
332+
// obtain a list of all Gecko pref states for which there is an enrollment value
333+
let mut set_state_list = Vec::new();
334+
state.gecko_prefs_with_state.iter().for_each(|(_, props)| {
335+
props.iter().for_each(|(_, pref_state)| {
336+
if pref_state.enrollment_value.is_some() {
337+
set_state_list.push(pref_state.clone());
338+
}
339+
});
335340
});
336-
});
337-
// tell the handler to set the aforementioned Gecko prefs
338-
self.handler.set_gecko_prefs_state(set_state_list);
341+
// tell the handler to set the aforementioned Gecko prefs
342+
self.handler.set_gecko_prefs_state(set_state_list);
343+
}
339344

340345
results
341346
}

components/nimbus/src/stateful/nimbus_client.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ impl NimbusClient {
227227
writer,
228228
&coenrolling_ids,
229229
self.gecko_prefs.clone(),
230+
true,
230231
)?;
231232
Ok(())
232233
}
@@ -846,7 +847,22 @@ impl NimbusClient {
846847
)?;
847848
}
848849

849-
writer.commit()?;
850+
let coenrolling_ids = self
851+
.coenrolling_feature_ids
852+
.iter()
853+
.map(|s| s.as_str())
854+
.collect();
855+
856+
// Registering the Gecko original values does not require a Gecko update,
857+
// but the cache does need to be refreshed.
858+
self.database_cache.commit_and_update(
859+
db,
860+
writer,
861+
&coenrolling_ids,
862+
self.gecko_prefs.clone(),
863+
false,
864+
)?;
865+
850866
Ok(())
851867
}
852868

components/nimbus/src/tests/helpers.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ impl TestMetrics {
177177
pub struct TestGeckoPrefHandlerState {
178178
pub prefs_set: Option<Vec<GeckoPrefState>>,
179179
pub original_prefs_state: Option<Vec<OriginalGeckoPref>>,
180+
pub set_gecko_prefs_state_call_count: u32,
180181
}
181182

182183
#[cfg(feature = "stateful")]
@@ -193,6 +194,7 @@ impl TestGeckoPrefHandler {
193194
state: Mutex::new(TestGeckoPrefHandlerState {
194195
prefs_set: None,
195196
original_prefs_state: None,
197+
set_gecko_prefs_state_call_count: 0,
196198
}),
197199
}
198200
}
@@ -205,10 +207,12 @@ impl GeckoPrefHandler for TestGeckoPrefHandler {
205207
}
206208

207209
fn set_gecko_prefs_state(&self, new_prefs_state: Vec<GeckoPrefState>) {
208-
self.state
210+
let mut state = self
211+
.state
209212
.lock()
210-
.expect("Unable to lock TestGeckoPrefHandler state")
211-
.prefs_set = Some(new_prefs_state);
213+
.expect("Unable to lock TestGeckoPrefHandler state");
214+
state.prefs_set = Some(new_prefs_state);
215+
state.set_gecko_prefs_state_call_count += 1;
212216
}
213217

214218
fn set_gecko_prefs_original_values(&self, original_prefs_state: Vec<OriginalGeckoPref>) {

components/nimbus/src/tests/stateful/test_gecko_prefs.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ fn test_gecko_pref_store_map_gecko_prefs_to_enrollment_slugs_and_update_store()
5656
&experiments,
5757
&experiment_enrollments,
5858
&experiments_by_slug,
59+
true,
5960
);
6061

6162
let handler = unsafe {
@@ -147,6 +148,7 @@ fn test_gecko_pref_store_map_gecko_prefs_to_enrollment_slugs_and_update_store_ex
147148
&experiments,
148149
&experiment_enrollments,
149150
&experiments_by_slug,
151+
true,
150152
);
151153

152154
let handler = unsafe {

components/nimbus/src/tests/stateful/test_nimbus.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,9 +2174,28 @@ fn register_previous_gecko_pref_states() -> Result<()> {
21742174
gecko_pref_state_2.clone(),
21752175
gecko_pref_state_3.clone(),
21762176
];
2177+
2178+
let call_count_before = client
2179+
.get_gecko_pref_store()
2180+
.state
2181+
.lock()
2182+
.unwrap()
2183+
.set_gecko_prefs_state_call_count;
2184+
21772185
let registration = client.register_previous_gecko_pref_states(&gecko_pref_states);
21782186
assert!(registration.is_ok());
21792187

2188+
// Registration must not send pref values to Gecko.
2189+
assert_eq!(
2190+
call_count_before,
2191+
client
2192+
.get_gecko_pref_store()
2193+
.state
2194+
.lock()
2195+
.unwrap()
2196+
.set_gecko_prefs_state_call_count
2197+
);
2198+
21802199
let db = client.db()?;
21812200
let reader = db.read()?;
21822201
let mut enrollments: Vec<ExperimentEnrollment> =

0 commit comments

Comments
 (0)