Skip to content

Commit a726b71

Browse files
feat(nns): Split the active_neurons_in_stable_memory into 2 flags (#3312)
# Why The previous set up for the feature flag `active_neurons_in_stable_memory` does not allow us to safely rollback if necessary, because the rolled back version would only look for active neurons in the heap memory, while some would still be in the stable memory until the timer picks them up (if the reverse migration is implemented). # What Use `allow_active_neurons_in_stable_memory` for whether the canister allows active neurons to be in stable memory, by checking stable memory when iterating/finding active neurons. Use `migrate_active_neurons_to_stable_memory` for whether the active neurons should be in stable memory, so that the migration task in the timer would move them accordingly. ## Launch/Rollback Plan With the new setup, we can: 1. Turn on `allow_active_neurons_in_stable_memory`. If any problems occur, we can roll it back. 2. If there is no problem found, we can turn on `migrate_active_neurons_to_stable_memory`. If any problems occur, we can roll back `migrate_active_neurons_to_stable_memory` and a later PR (which should be merged before launching) will do the reverse migration. We cannot rollback the 2 flags simultaneously (refer to the "Why" section above). 3. If we have to rollback `allow_active_neurons_in_stable_memory` at this point (however unlikely), we can rollback `migrate_active_neurons_to_stable_memory` first, and do another release to rollback `allow_active_neurons_in_stable_memory` after we confirm that the reverse migration has been completed.
1 parent 983a053 commit a726b71

File tree

7 files changed

+126
-64
lines changed

7 files changed

+126
-64
lines changed

rs/nns/governance/src/governance/benches.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ use crate::{
77
KnownNeuron, ListNeurons, Neuron as NeuronProto, ProposalData, Topic, Vote,
88
VotingPowerEconomics,
99
},
10-
temporarily_disable_active_neurons_in_stable_memory,
10+
temporarily_disable_allow_active_neurons_in_stable_memory,
11+
temporarily_disable_migrate_active_neurons_to_stable_memory,
1112
temporarily_disable_stable_memory_following_index,
12-
temporarily_enable_active_neurons_in_stable_memory,
13+
temporarily_enable_allow_active_neurons_in_stable_memory,
14+
temporarily_enable_migrate_active_neurons_to_stable_memory,
1315
temporarily_enable_stable_memory_following_index,
1416
test_utils::{MockEnvironment, StubCMC, StubIcpLedger},
1517
};
@@ -392,8 +394,9 @@ fn make_neuron(
392394

393395
#[bench(raw)]
394396
fn cascading_vote_stable_neurons_with_heap_index() -> BenchResult {
395-
let _a = temporarily_enable_active_neurons_in_stable_memory();
397+
let _a = temporarily_enable_allow_active_neurons_in_stable_memory();
396398
let _b = temporarily_disable_stable_memory_following_index();
399+
let _c = temporarily_enable_migrate_active_neurons_to_stable_memory();
397400

398401
cast_vote_cascade_helper(
399402
SetUpStrategy::Chain {
@@ -406,8 +409,9 @@ fn cascading_vote_stable_neurons_with_heap_index() -> BenchResult {
406409

407410
#[bench(raw)]
408411
fn cascading_vote_stable_everything() -> BenchResult {
409-
let _a = temporarily_enable_active_neurons_in_stable_memory();
412+
let _a = temporarily_enable_allow_active_neurons_in_stable_memory();
410413
let _b = temporarily_enable_stable_memory_following_index();
414+
let _c = temporarily_enable_migrate_active_neurons_to_stable_memory();
411415

412416
cast_vote_cascade_helper(
413417
SetUpStrategy::Chain {
@@ -420,8 +424,9 @@ fn cascading_vote_stable_everything() -> BenchResult {
420424

421425
#[bench(raw)]
422426
fn cascading_vote_all_heap() -> BenchResult {
423-
let _a = temporarily_disable_active_neurons_in_stable_memory();
427+
let _a = temporarily_disable_allow_active_neurons_in_stable_memory();
424428
let _b = temporarily_disable_stable_memory_following_index();
429+
let _c = temporarily_disable_migrate_active_neurons_to_stable_memory();
425430

426431
cast_vote_cascade_helper(
427432
SetUpStrategy::Chain {
@@ -434,8 +439,9 @@ fn cascading_vote_all_heap() -> BenchResult {
434439

435440
#[bench(raw)]
436441
fn cascading_vote_heap_neurons_stable_index() -> BenchResult {
437-
let _a = temporarily_disable_active_neurons_in_stable_memory();
442+
let _a = temporarily_disable_allow_active_neurons_in_stable_memory();
438443
let _b = temporarily_enable_stable_memory_following_index();
444+
let _c = temporarily_disable_migrate_active_neurons_to_stable_memory();
439445

440446
cast_vote_cascade_helper(
441447
SetUpStrategy::Chain {
@@ -448,8 +454,9 @@ fn cascading_vote_heap_neurons_stable_index() -> BenchResult {
448454

449455
#[bench(raw)]
450456
fn single_vote_all_stable() -> BenchResult {
451-
let _a = temporarily_enable_active_neurons_in_stable_memory();
457+
let _a = temporarily_enable_allow_active_neurons_in_stable_memory();
452458
let _b = temporarily_enable_stable_memory_following_index();
459+
let _c = temporarily_enable_migrate_active_neurons_to_stable_memory();
453460

454461
cast_vote_cascade_helper(
455462
SetUpStrategy::SingleVote { num_neurons: 151 },
@@ -459,8 +466,9 @@ fn single_vote_all_stable() -> BenchResult {
459466

460467
#[bench(raw)]
461468
fn centralized_following_all_stable() -> BenchResult {
462-
let _a = temporarily_enable_active_neurons_in_stable_memory();
469+
let _a = temporarily_enable_allow_active_neurons_in_stable_memory();
463470
let _b = temporarily_enable_stable_memory_following_index();
471+
let _c = temporarily_enable_migrate_active_neurons_to_stable_memory();
464472

465473
cast_vote_cascade_helper(
466474
SetUpStrategy::Centralized { num_neurons: 151 },
@@ -472,7 +480,8 @@ fn centralized_following_all_stable() -> BenchResult {
472480
fn compute_ballots_for_new_proposal_with_stable_neurons() -> BenchResult {
473481
let now_seconds = 1732817584;
474482

475-
let _f = temporarily_enable_active_neurons_in_stable_memory();
483+
let _a = temporarily_enable_allow_active_neurons_in_stable_memory();
484+
let _b = temporarily_enable_migrate_active_neurons_to_stable_memory();
476485
let neurons = (0..100)
477486
.map(|id| {
478487
(
@@ -558,13 +567,15 @@ fn list_neurons_benchmark() -> BenchResult {
558567
/// Benchmark list_neurons
559568
#[bench(raw)]
560569
fn list_neurons_stable() -> BenchResult {
561-
let _f = temporarily_enable_active_neurons_in_stable_memory();
570+
let _a = temporarily_enable_allow_active_neurons_in_stable_memory();
571+
let _b = temporarily_enable_migrate_active_neurons_to_stable_memory();
562572
list_neurons_benchmark()
563573
}
564574

565575
/// Benchmark list_neurons
566576
#[bench(raw)]
567577
fn list_neurons_heap() -> BenchResult {
568-
let _f = temporarily_disable_active_neurons_in_stable_memory();
578+
let _a = temporarily_disable_allow_active_neurons_in_stable_memory();
579+
let _b = temporarily_disable_migrate_active_neurons_to_stable_memory();
569580
list_neurons_benchmark()
570581
}

rs/nns/governance/src/lib.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,11 @@ thread_local! {
209209

210210
static ARE_SET_VISIBILITY_PROPOSALS_ENABLED: Cell<bool> = const { Cell::new(true) };
211211

212-
static ACTIVE_NEURONS_IN_STABLE_MEMORY_ENABLED: Cell<bool> = const { Cell::new(cfg!(feature = "test")) };
212+
static ALLOW_ACTIVE_NEURONS_IN_STABLE_MEMORY: Cell<bool> = const { Cell::new(cfg!(feature = "test")) };
213213

214214
static USE_STABLE_MEMORY_FOLLOWING_INDEX: Cell<bool> = const { Cell::new(cfg!(feature = "test")) };
215+
216+
static MIGRATE_ACTIVE_NEURONS_TO_STABLE_MEMORY: Cell<bool> = const { Cell::new(cfg!(feature = "test")) };
215217
}
216218

217219
thread_local! {
@@ -285,20 +287,20 @@ pub fn temporarily_disable_set_visibility_proposals() -> Temporary {
285287
Temporary::new(&ARE_SET_VISIBILITY_PROPOSALS_ENABLED, false)
286288
}
287289

288-
pub fn is_active_neurons_in_stable_memory_enabled() -> bool {
289-
ACTIVE_NEURONS_IN_STABLE_MEMORY_ENABLED.with(|ok| ok.get())
290+
pub fn allow_active_neurons_in_stable_memory() -> bool {
291+
ALLOW_ACTIVE_NEURONS_IN_STABLE_MEMORY.with(|ok| ok.get())
290292
}
291293

292294
/// Only integration tests should use this.
293295
#[cfg(any(test, feature = "canbench-rs", feature = "test"))]
294-
pub fn temporarily_enable_active_neurons_in_stable_memory() -> Temporary {
295-
Temporary::new(&ACTIVE_NEURONS_IN_STABLE_MEMORY_ENABLED, true)
296+
pub fn temporarily_enable_allow_active_neurons_in_stable_memory() -> Temporary {
297+
Temporary::new(&ALLOW_ACTIVE_NEURONS_IN_STABLE_MEMORY, true)
296298
}
297299

298300
/// Only integration tests should use this.
299301
#[cfg(any(test, feature = "canbench-rs", feature = "test"))]
300-
pub fn temporarily_disable_active_neurons_in_stable_memory() -> Temporary {
301-
Temporary::new(&ACTIVE_NEURONS_IN_STABLE_MEMORY_ENABLED, false)
302+
pub fn temporarily_disable_allow_active_neurons_in_stable_memory() -> Temporary {
303+
Temporary::new(&ALLOW_ACTIVE_NEURONS_IN_STABLE_MEMORY, false)
302304
}
303305

304306
pub fn use_stable_memory_following_index() -> bool {
@@ -317,6 +319,22 @@ pub fn temporarily_disable_stable_memory_following_index() -> Temporary {
317319
Temporary::new(&USE_STABLE_MEMORY_FOLLOWING_INDEX, false)
318320
}
319321

322+
pub fn migrate_active_neurons_to_stable_memory() -> bool {
323+
MIGRATE_ACTIVE_NEURONS_TO_STABLE_MEMORY.with(|ok| ok.get())
324+
}
325+
326+
/// Only integration tests should use this.
327+
#[cfg(any(test, feature = "canbench-rs", feature = "test"))]
328+
pub fn temporarily_enable_migrate_active_neurons_to_stable_memory() -> Temporary {
329+
Temporary::new(&MIGRATE_ACTIVE_NEURONS_TO_STABLE_MEMORY, true)
330+
}
331+
332+
/// Only integration tests should use this.
333+
#[cfg(any(test, feature = "canbench-rs", feature = "test"))]
334+
pub fn temporarily_disable_migrate_active_neurons_to_stable_memory() -> Temporary {
335+
Temporary::new(&MIGRATE_ACTIVE_NEURONS_TO_STABLE_MEMORY, false)
336+
}
337+
320338
pub fn decoder_config() -> DecoderConfig {
321339
let mut config = DecoderConfig::new();
322340
config.set_skipping_quota(DEFAULT_SKIPPING_QUOTA);

rs/nns/governance/src/neuron_data_validation.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
is_active_neurons_in_stable_memory_enabled,
2+
allow_active_neurons_in_stable_memory,
33
neuron::Neuron,
44
neuron_store::NeuronStore,
55
pb::v1::Topic,
@@ -225,7 +225,7 @@ impl ValidationInProgress {
225225
KnownNeuronIndexValidator,
226226
>::new()));
227227

228-
if !is_active_neurons_in_stable_memory_enabled() {
228+
if !allow_active_neurons_in_stable_memory() {
229229
tasks.push_back(Box::new(StableNeuronStoreValidator::new(
230230
INACTIVE_NEURON_VALIDATION_CHUNK_SIZE,
231231
)));
@@ -688,7 +688,7 @@ mod tests {
688688
neuron::{DissolveStateAndAge, NeuronBuilder},
689689
pb::v1::{neuron::Followees, KnownNeuronData},
690690
storage::{with_stable_neuron_indexes_mut, with_stable_neuron_store_mut},
691-
temporarily_disable_active_neurons_in_stable_memory,
691+
temporarily_disable_allow_active_neurons_in_stable_memory,
692692
};
693693

694694
thread_local! {
@@ -996,7 +996,7 @@ mod tests {
996996

997997
#[test]
998998
fn test_validator_invalid_issues_active_neuron_in_stable() {
999-
let _t = temporarily_disable_active_neurons_in_stable_memory();
999+
let _t = temporarily_disable_allow_active_neurons_in_stable_memory();
10001000

10011001
// Step 1: Cause an issue with active neuron in stable storage.
10021002
// Step 1.1 First create it as an inactive neuron so it can be added to stable storage.

rs/nns/governance/src/neuron_store.rs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use crate::{
2+
allow_active_neurons_in_stable_memory,
23
governance::{
34
Environment, TimeWarp, LOG_PREFIX, MIN_DISSOLVE_DELAY_FOR_VOTE_ELIGIBILITY_SECONDS,
45
},
5-
is_active_neurons_in_stable_memory_enabled,
6+
migrate_active_neurons_to_stable_memory,
67
neuron::types::Neuron,
78
neurons_fund::neurons_fund_neuron::pick_most_important_hotkeys,
89
pb::v1::{
@@ -319,10 +320,14 @@ pub struct NeuronStore {
319320
// NeuronStore) implements additional traits. Therefore, more elaborate wrapping is needed.
320321
clock: Box<dyn PracticalClock>,
321322

322-
// Whether to use stable memory for all neurons. This is a temporary flag to change the mode
323-
// of operation for the NeuronStore. Once all neurons are in stable memory, this will be
324-
// removed, as well as heap_neurons.
325-
use_stable_memory_for_all_neurons: bool,
323+
// Whether to allow active neurons in stable memory. When this is true, when finding/iterating
324+
// through active neurons, we need to check both heap and stable memory.
325+
allow_active_neurons_in_stable_memory: bool,
326+
327+
/// Whether to migrate active neurons to stable memory. This is a temporary flag to change the
328+
/// mode of operation for the NeuronStore. Once all neurons are in stable memory, this will be
329+
/// removed.
330+
migrate_active_neurons_to_stable_memory: bool,
326331

327332
// Temporary flag to determine which following index to use
328333
use_stable_following_index: bool,
@@ -338,8 +343,9 @@ impl PartialEq for NeuronStore {
338343
heap_neurons,
339344
topic_followee_index,
340345
clock: _,
341-
use_stable_memory_for_all_neurons: _,
346+
allow_active_neurons_in_stable_memory: _,
342347
use_stable_following_index: _,
348+
migrate_active_neurons_to_stable_memory: _,
343349
} = self;
344350

345351
*heap_neurons == other.heap_neurons && *topic_followee_index == other.topic_followee_index
@@ -352,8 +358,9 @@ impl Default for NeuronStore {
352358
heap_neurons: BTreeMap::new(),
353359
topic_followee_index: HeapNeuronFollowingIndex::new(BTreeMap::new()),
354360
clock: Box::new(IcClock::new()),
355-
use_stable_memory_for_all_neurons: false,
361+
allow_active_neurons_in_stable_memory: false,
356362
use_stable_following_index: false,
363+
migrate_active_neurons_to_stable_memory: false,
357364
}
358365
}
359366
}
@@ -368,8 +375,9 @@ impl NeuronStore {
368375
heap_neurons: BTreeMap::new(),
369376
topic_followee_index: HeapNeuronFollowingIndex::new(BTreeMap::new()),
370377
clock: Box::new(IcClock::new()),
371-
use_stable_memory_for_all_neurons: is_active_neurons_in_stable_memory_enabled(),
378+
allow_active_neurons_in_stable_memory: allow_active_neurons_in_stable_memory(),
372379
use_stable_following_index: use_stable_memory_following_index(),
380+
migrate_active_neurons_to_stable_memory: migrate_active_neurons_to_stable_memory(),
373381
};
374382

375383
// Adds the neurons one by one into neuron store.
@@ -400,8 +408,9 @@ impl NeuronStore {
400408
.collect(),
401409
topic_followee_index: proto_to_heap_topic_followee_index(topic_followee_index),
402410
clock,
403-
use_stable_memory_for_all_neurons: is_active_neurons_in_stable_memory_enabled(),
411+
allow_active_neurons_in_stable_memory: allow_active_neurons_in_stable_memory(),
404412
use_stable_following_index: use_stable_memory_following_index(),
413+
migrate_active_neurons_to_stable_memory: migrate_active_neurons_to_stable_memory(),
405414
}
406415
}
407416

@@ -515,7 +524,7 @@ impl NeuronStore {
515524
// has changed, e.g. after an upgrade (2) the neuron was active, but becomes inactive due to
516525
// passage of time.
517526
fn target_storage_location(&self, neuron: &Neuron) -> StorageLocation {
518-
if self.use_stable_memory_for_all_neurons || neuron.is_inactive(self.now()) {
527+
if self.migrate_active_neurons_to_stable_memory || neuron.is_inactive(self.now()) {
519528
StorageLocation::Stable
520529
} else {
521530
StorageLocation::Heap
@@ -851,7 +860,7 @@ impl NeuronStore {
851860
callback: impl for<'b> FnOnce(Box<dyn Iterator<Item = Cow<Neuron>> + 'b>) -> R,
852861
sections: NeuronSections,
853862
) -> R {
854-
if self.use_stable_memory_for_all_neurons {
863+
if self.allow_active_neurons_in_stable_memory {
855864
// Note, during migration, we still need heap_neurons, so we chain them onto the iterator
856865
with_stable_neuron_store(|stable_store| {
857866
let now = self.now();
@@ -1218,10 +1227,10 @@ impl NeuronStore {
12181227
neuron_id: &NeuronId,
12191228
modify: impl FnOnce(u64) -> Result<u64, String>,
12201229
) -> Result<(), NeuronStoreError> {
1221-
// When `use_stable_memory_for_all_neurons` is true, all the neurons SHOULD be in the stable
1230+
// When `allow_active_neurons_in_stable_memory` is true, all the neurons SHOULD be in the stable
12221231
// neuron store. Therefore, there is no need to move the neuron between heap/stable as it
12231232
// might become active/inactive due to the change of maturity.
1224-
if self.use_stable_memory_for_all_neurons {
1233+
if self.allow_active_neurons_in_stable_memory {
12251234
// The validity of this approach is based on the assumption that none of the neuron
12261235
// indexes can be affected by its maturity.
12271236
if self.heap_neurons.contains_key(&neuron_id.id) {
@@ -1342,7 +1351,7 @@ impl NeuronStore {
13421351

13431352
let is_neuron_inactive = neuron.is_inactive(self.now());
13441353

1345-
if self.use_stable_memory_for_all_neurons || is_neuron_inactive {
1354+
if self.allow_active_neurons_in_stable_memory || is_neuron_inactive {
13461355
None
13471356
} else {
13481357
// An active neuron in stable neuron store is invalid.

0 commit comments

Comments
 (0)