A simple map viewer

search.rs 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. use coord::LatLonDeg;
  2. use osmpbf::{Blob, BlobDecode, BlobReader, PrimitiveBlock};
  3. use query::{find_query_matches, QueryArgs, QueryKind};
  4. use scoped_threadpool::Pool;
  5. use std::collections::hash_set::HashSet;
  6. use std::path::{Path, PathBuf};
  7. use std::sync::mpsc::sync_channel;
  8. use std::thread;
  9. #[derive(Debug, Eq, PartialEq)]
  10. pub enum ControlFlow {
  11. Continue,
  12. Break,
  13. }
  14. impl<T, E> From<Result<T, E>> for ControlFlow
  15. {
  16. fn from(result: Result<T, E>) -> Self {
  17. match result {
  18. Ok(_) => ControlFlow::Continue,
  19. Err(_) => ControlFlow::Break,
  20. }
  21. }
  22. }
  23. enum WorkerMessage {
  24. PleaseStop,
  25. DoBlob(Box<Blob>),
  26. }
  27. pub fn par_search<P, F, G>(
  28. pbf_path: P,
  29. query_args: QueryArgs,
  30. found_func: F,
  31. finished_func: G,
  32. ) -> Result<thread::JoinHandle<()>, String>
  33. where P: AsRef<Path>,
  34. F: Fn(Vec<LatLonDeg>) -> ControlFlow + Send + 'static,
  35. G: Fn(Result<(), String>) + Send + 'static,
  36. {
  37. let pbf_path = PathBuf::from(pbf_path.as_ref());
  38. let handle = thread::spawn(move|| {
  39. let res = par_search_blocking(pbf_path, query_args, found_func);
  40. finished_func(res);
  41. });
  42. Ok(handle)
  43. }
  44. pub fn par_search_blocking<P, F>(
  45. pbf_path: P,
  46. query_args: QueryArgs,
  47. found_func: F,
  48. ) -> Result<(), String>
  49. where P: AsRef<Path>,
  50. F: Fn(Vec<LatLonDeg>) -> ControlFlow + Send + 'static,
  51. {
  52. let query = query_args.compile()?;
  53. let query = &query;
  54. let first_pass = move |block: &PrimitiveBlock, _: &()| {
  55. let mut matches = vec![];
  56. let mut way_node_ids = vec![];
  57. match query {
  58. &QueryKind::ValuePattern(ref query) => {
  59. find_query_matches(block, query, &mut matches, &mut way_node_ids);
  60. },
  61. &QueryKind::KeyValue(ref query) => {
  62. find_query_matches(block, query, &mut matches, &mut way_node_ids);
  63. },
  64. _ => {
  65. //TODO implement
  66. unimplemented!();
  67. },
  68. }
  69. (matches, way_node_ids)
  70. };
  71. let mut way_node_ids: HashSet<i64> = HashSet::new();
  72. par_iter_blobs(
  73. &pbf_path,
  74. || {},
  75. first_pass,
  76. |(matches, node_ids)| {
  77. way_node_ids.extend(&node_ids);
  78. found_func(matches)
  79. },
  80. )?;
  81. let way_node_ids = &way_node_ids;
  82. let second_pass = move |block: &PrimitiveBlock, _: &()| {
  83. let mut matches = vec![];
  84. for node in block.groups().flat_map(|g| g.nodes()) {
  85. if way_node_ids.contains(&node.id()) {
  86. let pos = LatLonDeg::new(node.lat(), node.lon());
  87. matches.push(pos);
  88. }
  89. }
  90. for node in block.groups().flat_map(|g| g.dense_nodes()) {
  91. if way_node_ids.contains(&node.id) {
  92. let pos = LatLonDeg::new(node.lat(), node.lon());
  93. matches.push(pos);
  94. }
  95. }
  96. matches
  97. };
  98. par_iter_blobs(
  99. &pbf_path,
  100. || {},
  101. second_pass,
  102. found_func,
  103. )
  104. }
  105. fn par_iter_blobs<P, D, R, IF, CF, RF>(
  106. pbf_path: P,
  107. init_func: IF,
  108. compute_func: CF,
  109. mut result_func: RF,
  110. ) -> Result<(), String>
  111. where P: AsRef<Path>,
  112. IF: Fn() -> D,
  113. CF: Fn(&PrimitiveBlock, &D) -> R + Send + Sync,
  114. RF: FnMut(R) -> ControlFlow,
  115. R: Send,
  116. D: Send,
  117. {
  118. let num_threads = ::num_cpus::get();
  119. let mut pool = Pool::new(num_threads as u32);
  120. pool.scoped(|scope| {
  121. let mut reader = BlobReader::from_path(&pbf_path)
  122. .map_err(|e| format!("{}", e))?;
  123. let mut chans = Vec::with_capacity(num_threads);
  124. let (result_tx, result_rx) = sync_channel::<(usize, Result<Option<R>, String>)>(0);
  125. for thread_id in 0..num_threads {
  126. let thread_data = init_func();
  127. let result_tx = result_tx.clone();
  128. let (request_tx, request_rx) = sync_channel::<WorkerMessage>(0);
  129. chans.push(request_tx);
  130. let compute = &compute_func;
  131. scope.execute(move || {
  132. for request in request_rx.iter() {
  133. match request {
  134. WorkerMessage::PleaseStop => return,
  135. WorkerMessage::DoBlob(blob) => {
  136. match blob.decode() {
  137. Ok(BlobDecode::OsmData(block)) => {
  138. let result = compute(&block, &thread_data);
  139. if result_tx.send((thread_id, Ok(Some(result)))).is_err() {
  140. return;
  141. }
  142. },
  143. //TODO also include other blob types in compute function
  144. Ok(_) => {
  145. if result_tx.send((thread_id, Ok(None))).is_err() {
  146. return;
  147. }
  148. },
  149. Err(err) => {
  150. let _ = result_tx.send((thread_id, Err(format!("{}", err))));
  151. return;
  152. },
  153. }
  154. }
  155. };
  156. }
  157. });
  158. }
  159. let mut stopped_threads = 0;
  160. // send initial message to each worker thread
  161. for channel in &chans {
  162. match reader.next() {
  163. Some(Ok(blob)) => {
  164. channel.send(WorkerMessage::DoBlob(Box::new(blob)))
  165. .map_err(|e| format!("{}", e))?;
  166. },
  167. Some(Err(err)) => {
  168. return Err(format!("{}", err));
  169. },
  170. None => {
  171. channel.send(WorkerMessage::PleaseStop)
  172. .map_err(|e| format!("{}", e))?;
  173. stopped_threads += 1;
  174. },
  175. }
  176. }
  177. if stopped_threads == num_threads {
  178. return Ok(());
  179. }
  180. for (thread_id, matches) in result_rx.iter() {
  181. match matches {
  182. Err(err) => return Err(err),
  183. Ok(Some(matches)) => {
  184. if result_func(matches) == ControlFlow::Break {
  185. break;
  186. }
  187. },
  188. _ => {},
  189. }
  190. match reader.next() {
  191. Some(Ok(blob)) => {
  192. chans[thread_id].send(WorkerMessage::DoBlob(Box::new(blob)))
  193. .map_err(|e| format!("{}", e))?;
  194. },
  195. Some(Err(err)) => {
  196. return Err(format!("{}", err));
  197. },
  198. None => {
  199. chans[thread_id].send(WorkerMessage::PleaseStop)
  200. .map_err(|e| format!("{}", e))?;
  201. stopped_threads += 1;
  202. if stopped_threads == num_threads {
  203. break;
  204. }
  205. }
  206. }
  207. }
  208. Ok(())
  209. })
  210. }