cfx_rpc/helpers/
poll_manager.rs

1#![allow(dead_code)]
2// Copyright 2015-2019 Parity Technologies (UK) Ltd.
3// This file is part of Parity Ethereum.
4
5// Parity Ethereum is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9
10// Parity Ethereum is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14
15// You should have received a copy of the GNU General Public License
16// along with Parity Ethereum.  If not, see <http://www.gnu.org/licenses/>.
17
18//! Indexes all rpc poll requests.
19
20use cfx_types::H128;
21use transient_hashmap::{StandardTimer, Timer, TransientHashMap};
22
23pub type PollId = H128;
24
25/// Indexes all poll requests.
26///
27/// Lazily garbage collects unused polls info.
28pub struct PollManager<F, T = StandardTimer>
29where T: Timer
30{
31    polls: TransientHashMap<PollId, F, T>,
32}
33
34impl<F> PollManager<F, StandardTimer> {
35    /// Creates new instance of indexer
36    pub fn new(lifetime: u32) -> Self {
37        PollManager::new_with_timer(Default::default(), lifetime)
38    }
39}
40
41impl<F, T> PollManager<F, T>
42where T: Timer
43{
44    pub fn new_with_timer(timer: T, lifetime: u32) -> Self {
45        PollManager {
46            polls: TransientHashMap::new_with_timer(lifetime, timer),
47        }
48    }
49
50    /// Returns id which can be used for new poll.
51    ///
52    /// Stores information when last poll happend.
53    pub fn create_poll(&mut self, filter: F) -> PollId {
54        self.polls.prune();
55
56        let id = loop {
57            let id = PollId::random();
58            if self.polls.contains_key(&id) {
59                continue;
60            }
61
62            break id;
63        };
64
65        self.polls.insert(id, filter);
66
67        id
68    }
69
70    // Implementation is always using `poll_mut`
71    /// Get a reference to stored poll filter
72    pub fn poll(&mut self, id: &PollId) -> Option<&F> {
73        self.polls.prune();
74        self.polls.get(id)
75    }
76
77    /// Get a mutable reference to stored poll filter
78    pub fn poll_mut(&mut self, id: &PollId) -> Option<&mut F> {
79        self.polls.prune();
80        self.polls.get_mut(id)
81    }
82
83    /// Removes poll info.
84    pub fn remove_poll(&mut self, id: &PollId) -> bool {
85        self.polls.remove(id).is_some()
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::PollManager;
92    use std::cell::Cell;
93    use transient_hashmap::Timer;
94
95    struct TestTimer<'a> {
96        time: &'a Cell<i64>,
97    }
98
99    impl<'a> Timer for TestTimer<'a> {
100        fn get_time(&self) -> i64 { self.time.get() }
101    }
102
103    #[test]
104    fn test_poll_indexer() {
105        let time = Cell::new(0);
106        let timer = TestTimer { time: &time };
107
108        let mut indexer = PollManager::new_with_timer(timer, 60);
109        let id1 = indexer.create_poll(20);
110        let id2 = indexer.create_poll(20);
111        assert_ne!(id1, id2);
112
113        time.set(10);
114        *indexer.poll_mut(&id1).unwrap() = 21;
115        assert_eq!(*indexer.poll(&id1).unwrap(), 21);
116        assert_eq!(*indexer.poll(&id2).unwrap(), 20);
117
118        time.set(30);
119        *indexer.poll_mut(&id2).unwrap() = 23;
120        assert_eq!(*indexer.poll(&id2).unwrap(), 23);
121
122        time.set(75);
123        assert!(indexer.poll(&id1).is_none());
124        assert_eq!(*indexer.poll(&id2).unwrap(), 23);
125
126        indexer.remove_poll(&id2);
127        assert!(indexer.poll(&id2).is_none());
128    }
129}