radix_engine/kernel/
substate_locks.rs1use crate::internal_prelude::*;
2
3pub struct SubstateLockError;
4
5#[derive(Debug, Copy, Clone, PartialEq, Eq, Sbor)]
6pub enum SubstateLockState {
7 Read(usize),
8 Write,
9}
10
11impl SubstateLockState {
12 fn no_lock() -> Self {
13 Self::Read(0)
14 }
15
16 fn is_locked(&self) -> bool {
17 !matches!(self, SubstateLockState::Read(0usize))
18 }
19
20 fn try_lock(&mut self, read_only: bool) -> Result<(), SubstateLockError> {
21 match self {
22 SubstateLockState::Read(n) => {
23 if read_only {
24 *n = *n + 1;
25 } else {
26 if *n != 0 {
27 return Err(SubstateLockError);
28 }
29 *self = SubstateLockState::Write;
30 }
31 }
32 SubstateLockState::Write => {
33 return Err(SubstateLockError);
34 }
35 }
36
37 Ok(())
38 }
39
40 fn unlock(&mut self) {
41 match self {
42 SubstateLockState::Read(n) => {
43 *n = *n - 1;
44 }
45 SubstateLockState::Write => {
46 *self = SubstateLockState::no_lock();
47 }
48 }
49 }
50}
51
52pub struct SubstateLocks<D> {
53 locks: IndexMap<u32, (NodeId, PartitionNumber, SubstateKey, D)>,
54 substate_lock_states: NonIterMap<(NodeId, PartitionNumber, SubstateKey), SubstateLockState>,
55 node_num_locked: NonIterMap<NodeId, usize>,
56 next_lock_id: u32,
57}
58
59impl<D> SubstateLocks<D> {
60 pub fn new() -> Self {
61 Self {
62 locks: index_map_new(),
63 substate_lock_states: NonIterMap::new(),
64 node_num_locked: NonIterMap::new(),
65 next_lock_id: 0u32,
66 }
67 }
68
69 fn new_lock_handle(
70 &mut self,
71 node_id: &NodeId,
72 partition_num: PartitionNumber,
73 substate_key: &SubstateKey,
74 data: D,
75 ) -> u32 {
76 let new_lock = self.next_lock_id;
77 self.locks.insert(
78 new_lock,
79 (*node_id, partition_num, substate_key.clone(), data),
80 );
81 self.next_lock_id += 1;
82 new_lock
83 }
84
85 pub fn node_is_locked(&self, node_id: &NodeId) -> bool {
86 self.node_num_locked
87 .get(node_id)
88 .map(|e| *e > 0)
89 .unwrap_or(false)
90 }
91
92 pub fn is_locked(
93 &self,
94 node_id: &NodeId,
95 partition_num: PartitionNumber,
96 substate_key: &SubstateKey,
97 ) -> bool {
98 if let Some(state) =
99 self.substate_lock_states
100 .get(&(node_id.clone(), partition_num, substate_key.clone()))
101 {
102 state.is_locked()
103 } else {
104 false
105 }
106 }
107
108 pub fn lock(
109 &mut self,
110 node_id: &NodeId,
111 partition_num: PartitionNumber,
112 substate_key: &SubstateKey,
113 read_only: bool,
114 data: D,
115 ) -> Option<u32> {
116 let lock_state = self
117 .substate_lock_states
118 .entry((node_id.clone(), partition_num, substate_key.clone()))
119 .or_insert(SubstateLockState::no_lock());
120 match lock_state.try_lock(read_only) {
121 Ok(()) => {}
122 Err(_) => {
123 return None;
124 }
125 }
126
127 let count = self.node_num_locked.entry(*node_id).or_insert(0);
128 *count = *count + 1;
129
130 let handle = self.new_lock_handle(node_id, partition_num, substate_key, data);
131 Some(handle)
132 }
133
134 pub fn get(&self, handle: u32) -> &(NodeId, PartitionNumber, SubstateKey, D) {
135 self.locks.get(&handle).unwrap()
136 }
137
138 pub fn get_mut(&mut self, handle: u32) -> &mut (NodeId, PartitionNumber, SubstateKey, D) {
139 self.locks.get_mut(&handle).unwrap()
140 }
141
142 pub fn unlock(&mut self, handle: u32) -> (NodeId, PartitionNumber, SubstateKey, D) {
143 let (node_id, partition_num, substate_key, data) = self.locks.swap_remove(&handle).unwrap();
144 let full_key = (node_id, partition_num, substate_key);
145
146 let lock_state = self.substate_lock_states.get_mut(&full_key).unwrap();
147 lock_state.unlock();
148
149 let count = self.node_num_locked.entry(node_id).or_insert(0);
150 *count = *count - 1;
151
152 (full_key.0, full_key.1, full_key.2, data)
153 }
154}