1use crate::client::Client;
4use crate::error::{Error, Result};
5use crate::events::lock;
6use crate::frame::MAX_META_BYTES;
7use crate::wire::*;
8use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
9use std::sync::Mutex;
10
11pub(crate) const MAX_BATCH_ITEMS: usize = 4096;
13
14pub type StatResult = Result<FileInfo>;
16
17pub(crate) fn item<T>(r: Result<T>) -> Result<Result<T>> {
19 match r {
20 Err(e @ Error::Server { .. }) => Ok(Err(e)),
21 other => other.map(Ok),
22 }
23}
24
25pub(crate) fn batch_errors(n: usize, errors: Vec<BatchItemError>) -> Result<Vec<Option<Error>>> {
27 let mut out: Vec<Option<Error>> = (0..n).map(|_| None).collect();
28 for e in errors {
29 let slot = out
30 .get_mut(e.index as usize)
31 .ok_or_else(|| Error::Protocol(format!("batch error index {} out of {n}", e.index)))?;
32 *slot = Some(Error::Server {
33 code: e.code,
34 message: e.message,
35 });
36 }
37 Ok(out)
38}
39
40pub(crate) fn par_map<T: Send>(n: usize, workers: usize, job: impl Fn(usize) -> Result<T> + Sync) -> Result<Vec<T>> {
43 if n <= 1 || workers <= 1 {
44 return (0..n).map(job).collect();
45 }
46 let next = AtomicUsize::new(0);
47 let failed = AtomicBool::new(false);
48 let slots: Mutex<Vec<Option<Result<T>>>> = Mutex::new((0..n).map(|_| None).collect());
49 std::thread::scope(|sc| {
50 for _ in 0..workers.min(n) {
51 sc.spawn(|| loop {
52 let i = next.fetch_add(1, Ordering::SeqCst);
53 if i >= n || failed.load(Ordering::SeqCst) {
54 break;
55 }
56 let r = job(i);
57 if r.is_err() {
58 failed.store(true, Ordering::SeqCst);
59 }
60 lock(&slots)[i] = Some(r);
61 });
62 }
63 });
64 let mut out = Vec::with_capacity(n);
65 for r in slots
66 .into_inner()
67 .unwrap_or_else(|e| e.into_inner())
68 .into_iter()
69 .flatten()
70 {
71 out.push(r?);
72 }
73 Ok(out)
74}
75
76impl Client {
77 pub fn stat_batch(&self, paths: &[String]) -> Result<Vec<StatResult>> {
80 let meta_budget = MAX_META_BYTES as usize / 2;
81 let mut parts = Vec::new();
82 let mut start = 0;
83 while start < paths.len() {
84 let (mut end, mut size) = (start, 0usize);
85 while end < paths.len()
86 && end - start < MAX_BATCH_ITEMS
87 && (end == start || size + paths[end].len() + 8 <= meta_budget)
88 {
89 size += paths[end].len() + 8;
90 end += 1;
91 }
92 parts.push(&paths[start..end]);
93 start = end;
94 }
95 let chunks = par_map(parts.len(), self.pool_size(), |i| {
96 let part = parts[i];
97 let r: StatBatchResponse = self.unary(method::STAT_BATCH, &StatBatchRequest { paths: part.to_vec() })?;
98 if r.infos.len() != part.len() {
99 return Err(Error::Protocol(format!(
100 "stat batch returned {} infos for {} paths",
101 r.infos.len(),
102 part.len()
103 )));
104 }
105 let mut errs = batch_errors(part.len(), r.errors)?;
106 Ok(
107 r.infos
108 .into_iter()
109 .enumerate()
110 .map(|(i, info)| match errs[i].take() {
111 Some(e) => Err(e),
112 None => Ok(info),
113 })
114 .collect::<Vec<_>>(),
115 )
116 })?;
117 Ok(chunks.into_iter().flatten().collect())
118 }
119
120 pub fn read_file(&self, path: &str) -> Result<Vec<u8>> {
123 let (data, limit) = self
124 .run_any(|c| {
125 let req = ReadFileRequest {
126 path: path.into(),
127 max_bytes: c.max_payload() as u64,
128 };
129 let (r, data) = c.call_msg::<ReadFileResponse>(method::READ_FILE, &req, &[])?;
130 if r.count as usize != data.len() {
131 return Err(Error::Protocol(format!(
132 "read file count {} payload {}",
133 r.count,
134 data.len()
135 )));
136 }
137 Ok((data, c.max_payload()))
138 })?
139 .0;
140 if data.len() < limit {
141 return Ok(data);
142 }
143 let f = self.open(path, open_flag::READ_ONLY, 0)?;
144 let mut out = Vec::new();
145 loop {
146 let part = f.read_at(out.len() as u64, limit)?;
147 let short = part.len() < limit;
148 out.extend_from_slice(&part);
149 if short {
150 return Ok(out);
151 }
152 }
153 }
154
155 pub fn write_file(&self, path: &str, data: &[u8], truncate: bool) -> Result<()> {
158 let sent = self
159 .run_any(|c| {
160 if data.len() > c.max_payload() {
161 return Ok(false);
162 }
163 let req = WriteFileRequest {
164 path: path.into(),
165 truncate,
166 };
167 let (r, _) = c.call_msg::<WriteFileResponse>(method::WRITE_FILE, &req, data)?;
168 if r.count as usize != data.len() {
169 return Err(Error::Protocol(format!(
170 "write file count {} for {} bytes",
171 r.count,
172 data.len()
173 )));
174 }
175 Ok(true)
176 })?
177 .0;
178 if sent {
179 return Ok(());
180 }
181 let mut flags = open_flag::WRITE_ONLY | open_flag::CREATE;
182 if truncate {
183 flags |= open_flag::TRUNC;
184 }
185 let f = self.open(path, flags, 0o644)?;
186 f.write_at(0, data)?;
187 f.close()
188 }
189}