Skip to main content

tyozo/
locks.rs

1use std::collections::HashMap;
2use std::sync::{Arc, Mutex};
3
4#[derive(Default, Debug)]
5pub struct Locks {
6    // NOTE sync::RwLock で出来そうだが
7    // ライフタイムの関係で今の自分の実力ではよく分からなかったので
8    // RWLock enumで管理するようにしている。
9    // TODO @k-nasa コレで良いのか判断してくれ! deadline: 2020/2/31
10    hashmap: Arc<Mutex<HashMap<String, RWLock>>>,
11}
12
13#[derive(Debug, PartialOrd, PartialEq)]
14enum RWLock {
15    Read(usize),
16    Write,
17}
18
19impl Locks {
20    pub fn new() -> Locks {
21        Locks {
22            hashmap: Arc::new(Mutex::new(HashMap::new())),
23        }
24    }
25
26    pub fn read_lock(&mut self, key: &str) {
27        // FIXME Write lock の開放をループで待って良いのか?という気持ち
28
29        loop {
30            let mut hashmap = self.hashmap.lock().unwrap();
31
32            if let Some(lock) = hashmap.get_mut(key) {
33                match lock {
34                    RWLock::Read(count) => *count += 1,
35                    RWLock::Write => continue,
36                };
37                break;
38            } else {
39                hashmap.insert(key.to_owned(), RWLock::Read(1));
40                break;
41            }
42        }
43    }
44
45    pub fn read_unlock(&mut self, key: &str) {
46        // FIXME refactor this method
47        // Resultを返すようにしましょう
48
49        let mut hashmap = self.hashmap.lock().unwrap();
50
51        if let Some(lock) = hashmap.get_mut(key) {
52            match lock {
53                RWLock::Read(count) => {
54                    *count -= 1;
55                    if *count == 0 {
56                        hashmap.remove(key);
57                    }
58                }
59                RWLock::Write => panic!("Attempting to release write lock"),
60            };
61        } else {
62            panic!("not found read lock")
63        }
64    }
65
66    pub fn write_lock(&mut self, key: &str) {
67        // FIXME read lock の開放をループで待って良いのか?という気持ち
68        loop {
69            let mut hashmap = self.hashmap.lock().unwrap();
70
71            if let Some(lock) = hashmap.get_mut(key) {
72                match lock {
73                    RWLock::Read(0) => {
74                        hashmap.insert(key.to_owned(), RWLock::Write);
75                        break;
76                    }
77                    _ => continue,
78                };
79            } else {
80                hashmap.insert(key.to_owned(), RWLock::Write);
81                break;
82            }
83        }
84    }
85
86    pub fn write_unlock(&mut self, key: &str) {
87        // FIXME refactor this method
88        // Resultを返すようにしましょう
89
90        let mut hashmap = self.hashmap.lock().unwrap();
91
92        if let Some(lock) = hashmap.get_mut(key) {
93            match lock {
94                RWLock::Write => hashmap.remove(key),
95                RWLock::Read(_) => panic!("Attempting to release read lock"),
96            };
97        } else {
98            panic!("not found write lock")
99        }
100    }
101}
102
103#[test]
104fn test_read_lock() {
105    let mut locks = Locks::new();
106
107    let key = "key";
108
109    locks.read_lock(key);
110    locks.read_lock(key);
111    locks.read_lock(key);
112    locks.read_lock(key);
113
114    let hashmap = locks.hashmap.lock().unwrap();
115    let lock = hashmap.get(key).unwrap();
116
117    assert_eq!(lock, &RWLock::Read(4));
118}
119
120#[test]
121fn test_read_unlock() {
122    let mut locks = Locks::new();
123
124    let key = "key";
125
126    locks.read_lock(key);
127    locks.read_unlock(key);
128
129    let hashmap = locks.hashmap.lock().unwrap();
130    assert!(hashmap.get(key).is_none());
131}
132
133#[test]
134fn test_write_lock() {
135    let mut locks = Locks::new();
136
137    let key = "key";
138
139    locks.write_lock(key);
140
141    let hashmap = locks.hashmap.lock().unwrap();
142    let lock = hashmap.get(key).unwrap();
143
144    assert_eq!(lock, &RWLock::Write);
145}
146
147#[test]
148fn test_write_unlock() {
149    let mut locks = Locks::new();
150
151    let key = "key";
152
153    locks.write_lock(key);
154    locks.write_unlock(key);
155
156    let hashmap = locks.hashmap.lock().unwrap();
157    assert!(hashmap.get(key).is_none());
158}
159
160#[test]
161#[should_panic]
162fn test_write_unlock_panic_when_not_found_key() {
163    let mut locks = Locks::new();
164
165    locks.write_unlock("not found key");
166}
167
168#[test]
169#[should_panic]
170fn test_write_unlock_panic_when_read_lock() {
171    let mut locks = Locks::new();
172
173    locks.read_lock("key");
174    locks.write_unlock("key");
175}
176
177#[test]
178#[should_panic]
179fn test_read_unlock_panic_when_not_found_key() {
180    let mut locks = Locks::new();
181
182    locks.read_unlock("not found key");
183}
184
185#[test]
186#[should_panic]
187fn test_write_unlock_panic_when_write_lock() {
188    let mut locks = Locks::new();
189
190    locks.write_lock("key");
191    locks.read_unlock("key");
192}