2019-06-10 18:15:39 -07:00
|
|
|
use hashbrown::HashMap;
|
2019-04-15 17:15:50 -07:00
|
|
|
use log::*;
|
2019-05-30 21:31:35 -07:00
|
|
|
use serde::{Deserialize, Serialize};
|
2019-04-15 17:15:50 -07:00
|
|
|
use solana_sdk::pubkey::Pubkey;
|
2019-06-10 18:15:39 -07:00
|
|
|
use std::collections;
|
|
|
|
use std::collections::HashSet;
|
2019-04-15 17:15:50 -07:00
|
|
|
|
|
|
|
pub type Fork = u64;
|
|
|
|
|
2019-05-30 21:31:35 -07:00
|
|
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
2019-04-15 17:15:50 -07:00
|
|
|
pub struct AccountsIndex<T> {
|
2019-05-30 21:31:35 -07:00
|
|
|
#[serde(skip)]
|
|
|
|
pub account_maps: HashMap<Pubkey, Vec<(Fork, T)>>,
|
|
|
|
|
|
|
|
pub roots: HashSet<Fork>,
|
|
|
|
|
2019-04-15 17:15:50 -07:00
|
|
|
//This value that needs to be stored to recover the index from AppendVec
|
2019-04-23 09:56:36 -07:00
|
|
|
pub last_root: Fork,
|
2019-04-15 17:15:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Clone> AccountsIndex<T> {
|
|
|
|
/// Get an account
|
|
|
|
/// The latest account that appears in `ancestors` or `roots` is returned.
|
2019-06-10 18:15:39 -07:00
|
|
|
pub fn get(
|
|
|
|
&self,
|
|
|
|
pubkey: &Pubkey,
|
|
|
|
ancestors: &collections::HashMap<Fork, usize>,
|
|
|
|
) -> Option<(&T, Fork)> {
|
2019-04-15 17:15:50 -07:00
|
|
|
let list = self.account_maps.get(pubkey)?;
|
|
|
|
let mut max = 0;
|
|
|
|
let mut rv = None;
|
|
|
|
for e in list.iter().rev() {
|
|
|
|
if e.0 >= max && (ancestors.get(&e.0).is_some() || self.is_root(e.0)) {
|
|
|
|
trace!("GET {} {:?}", e.0, ancestors);
|
2019-05-06 07:31:50 -07:00
|
|
|
rv = Some((&e.1, e.0));
|
2019-04-15 17:15:50 -07:00
|
|
|
max = e.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rv
|
|
|
|
}
|
|
|
|
|
2019-06-10 18:15:39 -07:00
|
|
|
pub fn insert(
|
|
|
|
&mut self,
|
|
|
|
fork: Fork,
|
|
|
|
pubkey: &Pubkey,
|
|
|
|
account_info: T,
|
|
|
|
reclaims: &mut Vec<(Fork, T)>,
|
|
|
|
) {
|
|
|
|
let last_root = self.last_root;
|
|
|
|
let roots = &self.roots;
|
|
|
|
let fork_vec = self
|
|
|
|
.account_maps
|
|
|
|
.entry(*pubkey)
|
|
|
|
.or_insert_with(|| (Vec::with_capacity(32)));
|
2019-04-15 17:15:50 -07:00
|
|
|
|
|
|
|
// filter out old entries
|
2019-06-10 18:15:39 -07:00
|
|
|
reclaims.extend(fork_vec.iter().filter(|(f, _)| *f == fork).cloned());
|
2019-04-15 17:15:50 -07:00
|
|
|
fork_vec.retain(|(f, _)| *f != fork);
|
|
|
|
|
|
|
|
// add the new entry
|
|
|
|
fork_vec.push((fork, account_info));
|
|
|
|
|
2019-06-10 18:15:39 -07:00
|
|
|
reclaims.extend(
|
2019-04-15 17:15:50 -07:00
|
|
|
fork_vec
|
|
|
|
.iter()
|
2019-06-10 18:15:39 -07:00
|
|
|
.filter(|(fork, _)| Self::is_purged(roots, last_root, *fork))
|
2019-04-15 17:15:50 -07:00
|
|
|
.cloned(),
|
|
|
|
);
|
2019-06-10 18:15:39 -07:00
|
|
|
fork_vec.retain(|(fork, _)| !Self::is_purged(roots, last_root, *fork));
|
2019-04-15 17:15:50 -07:00
|
|
|
}
|
2019-05-30 21:31:35 -07:00
|
|
|
|
|
|
|
pub fn add_index(&mut self, fork: Fork, pubkey: &Pubkey, account_info: T) {
|
|
|
|
let entry = self.account_maps.entry(*pubkey).or_insert_with(|| vec![]);
|
|
|
|
entry.push((fork, account_info));
|
|
|
|
}
|
|
|
|
|
2019-06-10 18:15:39 -07:00
|
|
|
pub fn is_purged(roots: &HashSet<Fork>, last_root: Fork, fork: Fork) -> bool {
|
|
|
|
!roots.contains(&fork) && fork < last_root
|
2019-04-15 17:15:50 -07:00
|
|
|
}
|
2019-06-10 18:15:39 -07:00
|
|
|
|
2019-04-15 17:15:50 -07:00
|
|
|
pub fn is_root(&self, fork: Fork) -> bool {
|
|
|
|
self.roots.contains(&fork)
|
|
|
|
}
|
2019-06-10 18:15:39 -07:00
|
|
|
|
2019-04-15 17:15:50 -07:00
|
|
|
pub fn add_root(&mut self, fork: Fork) {
|
2019-04-28 10:27:37 -07:00
|
|
|
assert!(
|
|
|
|
(self.last_root == 0 && fork == 0) || (fork > self.last_root),
|
|
|
|
"new roots must be increasing"
|
|
|
|
);
|
|
|
|
self.last_root = fork;
|
2019-04-15 17:15:50 -07:00
|
|
|
self.roots.insert(fork);
|
|
|
|
}
|
|
|
|
/// Remove the fork when the storage for the fork is freed
|
|
|
|
/// Accounts no longer reference this fork.
|
|
|
|
pub fn cleanup_dead_fork(&mut self, fork: Fork) {
|
|
|
|
self.roots.remove(&fork);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use solana_sdk::signature::{Keypair, KeypairUtil};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_get_empty() {
|
|
|
|
let key = Keypair::new();
|
|
|
|
let index = AccountsIndex::<bool>::default();
|
2019-06-10 18:15:39 -07:00
|
|
|
let ancestors = collections::HashMap::new();
|
2019-04-15 17:15:50 -07:00
|
|
|
assert_eq!(index.get(&key.pubkey(), &ancestors), None);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_insert_no_ancestors() {
|
|
|
|
let key = Keypair::new();
|
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
2019-06-10 18:15:39 -07:00
|
|
|
let mut gc = Vec::new();
|
|
|
|
index.insert(0, &key.pubkey(), true, &mut gc);
|
2019-04-15 17:15:50 -07:00
|
|
|
assert!(gc.is_empty());
|
|
|
|
|
2019-06-10 18:15:39 -07:00
|
|
|
let ancestors = collections::HashMap::new();
|
2019-04-15 17:15:50 -07:00
|
|
|
assert_eq!(index.get(&key.pubkey(), &ancestors), None);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_insert_wrong_ancestors() {
|
|
|
|
let key = Keypair::new();
|
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
2019-06-10 18:15:39 -07:00
|
|
|
let mut gc = Vec::new();
|
|
|
|
index.insert(0, &key.pubkey(), true, &mut gc);
|
2019-04-15 17:15:50 -07:00
|
|
|
assert!(gc.is_empty());
|
|
|
|
|
|
|
|
let ancestors = vec![(1, 1)].into_iter().collect();
|
|
|
|
assert_eq!(index.get(&key.pubkey(), &ancestors), None);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_insert_with_ancestors() {
|
|
|
|
let key = Keypair::new();
|
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
2019-06-10 18:15:39 -07:00
|
|
|
let mut gc = Vec::new();
|
|
|
|
index.insert(0, &key.pubkey(), true, &mut gc);
|
2019-04-15 17:15:50 -07:00
|
|
|
assert!(gc.is_empty());
|
|
|
|
|
|
|
|
let ancestors = vec![(0, 0)].into_iter().collect();
|
2019-05-06 07:31:50 -07:00
|
|
|
assert_eq!(index.get(&key.pubkey(), &ancestors), Some((&true, 0)));
|
2019-04-15 17:15:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_is_root() {
|
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
|
|
|
assert!(!index.is_root(0));
|
|
|
|
index.add_root(0);
|
|
|
|
assert!(index.is_root(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_insert_with_root() {
|
|
|
|
let key = Keypair::new();
|
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
2019-06-10 18:15:39 -07:00
|
|
|
let mut gc = Vec::new();
|
|
|
|
index.insert(0, &key.pubkey(), true, &mut gc);
|
2019-04-15 17:15:50 -07:00
|
|
|
assert!(gc.is_empty());
|
|
|
|
|
|
|
|
let ancestors = vec![].into_iter().collect();
|
|
|
|
index.add_root(0);
|
2019-05-06 07:31:50 -07:00
|
|
|
assert_eq!(index.get(&key.pubkey(), &ancestors), Some((&true, 0)));
|
2019-04-15 17:15:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_is_purged() {
|
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
2019-06-10 18:15:39 -07:00
|
|
|
assert!(!AccountsIndex::<bool>::is_purged(
|
|
|
|
&index.roots,
|
|
|
|
index.last_root,
|
|
|
|
0
|
|
|
|
));
|
2019-04-15 17:15:50 -07:00
|
|
|
index.add_root(1);
|
2019-06-10 18:15:39 -07:00
|
|
|
assert!(AccountsIndex::<bool>::is_purged(
|
|
|
|
&index.roots,
|
|
|
|
index.last_root,
|
|
|
|
0
|
|
|
|
));
|
2019-04-15 17:15:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_max_last_root() {
|
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
|
|
|
index.add_root(1);
|
|
|
|
assert_eq!(index.last_root, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-04-28 10:27:37 -07:00
|
|
|
#[should_panic]
|
|
|
|
fn test_max_last_root_old() {
|
2019-04-15 17:15:50 -07:00
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
|
|
|
index.add_root(1);
|
|
|
|
index.add_root(0);
|
2019-04-28 10:27:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_cleanup_first() {
|
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
|
|
|
index.add_root(0);
|
|
|
|
index.add_root(1);
|
2019-04-15 17:15:50 -07:00
|
|
|
index.cleanup_dead_fork(0);
|
|
|
|
assert!(index.is_root(1));
|
|
|
|
assert!(!index.is_root(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_cleanup_last() {
|
|
|
|
//this behavior might be undefined, clean up should only occur on older forks
|
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
|
|
|
index.add_root(0);
|
2019-04-28 10:27:37 -07:00
|
|
|
index.add_root(1);
|
2019-04-15 17:15:50 -07:00
|
|
|
index.cleanup_dead_fork(1);
|
|
|
|
assert!(!index.is_root(1));
|
|
|
|
assert!(index.is_root(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_update_last_wins() {
|
|
|
|
let key = Keypair::new();
|
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
|
|
|
let ancestors = vec![(0, 0)].into_iter().collect();
|
2019-06-10 18:15:39 -07:00
|
|
|
let mut gc = Vec::new();
|
|
|
|
index.insert(0, &key.pubkey(), true, &mut gc);
|
2019-04-15 17:15:50 -07:00
|
|
|
assert!(gc.is_empty());
|
2019-05-06 07:31:50 -07:00
|
|
|
assert_eq!(index.get(&key.pubkey(), &ancestors), Some((&true, 0)));
|
2019-04-15 17:15:50 -07:00
|
|
|
|
2019-06-10 18:15:39 -07:00
|
|
|
let mut gc = Vec::new();
|
|
|
|
index.insert(0, &key.pubkey(), false, &mut gc);
|
2019-04-15 17:15:50 -07:00
|
|
|
assert_eq!(gc, vec![(0, true)]);
|
2019-05-06 07:31:50 -07:00
|
|
|
assert_eq!(index.get(&key.pubkey(), &ancestors), Some((&false, 0)));
|
2019-04-15 17:15:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_update_new_fork() {
|
|
|
|
let key = Keypair::new();
|
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
|
|
|
let ancestors = vec![(0, 0)].into_iter().collect();
|
2019-06-10 18:15:39 -07:00
|
|
|
let mut gc = Vec::new();
|
|
|
|
index.insert(0, &key.pubkey(), true, &mut gc);
|
2019-04-15 17:15:50 -07:00
|
|
|
assert!(gc.is_empty());
|
2019-06-10 18:15:39 -07:00
|
|
|
index.insert(1, &key.pubkey(), false, &mut gc);
|
2019-04-15 17:15:50 -07:00
|
|
|
assert!(gc.is_empty());
|
2019-05-06 07:31:50 -07:00
|
|
|
assert_eq!(index.get(&key.pubkey(), &ancestors), Some((&true, 0)));
|
2019-04-15 17:15:50 -07:00
|
|
|
let ancestors = vec![(1, 0)].into_iter().collect();
|
2019-05-06 07:31:50 -07:00
|
|
|
assert_eq!(index.get(&key.pubkey(), &ancestors), Some((&false, 1)));
|
2019-04-15 17:15:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_update_gc_purged_fork() {
|
|
|
|
let key = Keypair::new();
|
|
|
|
let mut index = AccountsIndex::<bool>::default();
|
2019-06-10 18:15:39 -07:00
|
|
|
let mut gc = Vec::new();
|
|
|
|
index.insert(0, &key.pubkey(), true, &mut gc);
|
2019-04-15 17:15:50 -07:00
|
|
|
assert!(gc.is_empty());
|
|
|
|
index.add_root(1);
|
2019-06-10 18:15:39 -07:00
|
|
|
index.insert(1, &key.pubkey(), false, &mut gc);
|
2019-04-15 17:15:50 -07:00
|
|
|
assert_eq!(gc, vec![(0, true)]);
|
|
|
|
let ancestors = vec![].into_iter().collect();
|
2019-05-06 07:31:50 -07:00
|
|
|
assert_eq!(index.get(&key.pubkey(), &ancestors), Some((&false, 1)));
|
2019-04-15 17:15:50 -07:00
|
|
|
}
|
|
|
|
}
|