1#![doc = include_str!("../README.md")]
19#![cfg_attr(docsrs, feature(doc_cfg))]
20#![cfg_attr(docsrs, doc(auto_cfg))]
21#![deny(missing_docs)]
22use std::sync::Arc;
23use std::sync::Mutex;
24
25use opendal_core::raw::*;
26use opendal_core::*;
27use rand::prelude::*;
28use rand::rngs::StdRng;
29
30#[derive(Clone, Debug)]
62pub struct ChaosLayer {
63 rng: Arc<Mutex<StdRng>>,
64 error_ratio: f64,
65}
66
67impl ChaosLayer {
68 pub fn new(error_ratio: f64) -> Self {
74 assert!(
75 (0.0..=1.0).contains(&error_ratio),
76 "error_ratio must between 0.0 and 1.0"
77 );
78 Self {
79 rng: Arc::new(Mutex::new(StdRng::from_rng(&mut rand::rng()))),
80 error_ratio,
81 }
82 }
83}
84
85impl Layer for ChaosLayer {
86 fn apply_service(&self, inner: Servicer) -> Servicer {
87 Arc::new(self.layer(inner))
88 }
89}
90
91impl ChaosLayer {
92 fn layer(&self, inner: Servicer) -> ChaosService {
93 ChaosService {
94 inner,
95 rng: self.rng.clone(),
96 error_ratio: self.error_ratio,
97 }
98 }
99}
100
101#[doc(hidden)]
102#[derive(Debug)]
103pub struct ChaosService {
104 inner: Servicer,
105 rng: Arc<Mutex<StdRng>>,
106 error_ratio: f64,
107}
108
109impl Service for ChaosService {
110 type Reader = ChaosReader<oio::Reader>;
111 type Writer = oio::Writer;
112 type Lister = oio::Lister;
113 type Deleter = oio::Deleter;
114 type Copier = oio::Copier;
115 type Composer = oio::Composer;
116
117 fn info(&self) -> ServiceInfo {
118 self.inner.info()
119 }
120
121 fn capability(&self) -> Capability {
122 let mut capability = self.inner.capability();
123 capability.write_can_copy_from = false;
124 capability
125 }
126
127 fn compose(&self, ctx: &OperationContext, to: &str, args: OpCompose) -> Result<Self::Composer> {
128 self.inner.compose(ctx, to, args)
129 }
130
131 async fn create_dir(
132 &self,
133 ctx: &OperationContext,
134 path: &str,
135 args: OpCreateDir,
136 ) -> Result<RpCreateDir> {
137 self.inner.create_dir(ctx, path, args).await
138 }
139
140 async fn stat(&self, ctx: &OperationContext, path: &str, args: OpStat) -> Result<RpStat> {
141 self.inner.stat(ctx, path, args).await
142 }
143
144 fn read(&self, ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
145 self.inner
146 .read(ctx, path, args)
147 .map(|r| ChaosReader::new(r, Arc::clone(&self.rng), self.error_ratio))
148 }
149
150 fn write(&self, ctx: &OperationContext, path: &str, args: OpWrite) -> Result<Self::Writer> {
151 self.inner.write(ctx, path, args)
152 }
153
154 fn copy(
155 &self,
156 ctx: &OperationContext,
157 from: &str,
158 to: &str,
159 args: OpCopy,
160 ) -> Result<Self::Copier> {
161 self.inner.copy(ctx, from, to, args)
162 }
163
164 fn list(&self, ctx: &OperationContext, path: &str, args: OpList) -> Result<Self::Lister> {
165 self.inner.list(ctx, path, args)
166 }
167
168 fn delete(&self, ctx: &OperationContext) -> Result<Self::Deleter> {
169 self.inner.delete(ctx)
170 }
171
172 async fn rename(
173 &self,
174 ctx: &OperationContext,
175 from: &str,
176 to: &str,
177 args: OpRename,
178 ) -> Result<RpRename> {
179 self.inner.rename(ctx, from, to, args).await
180 }
181
182 async fn restore(
183 &self,
184 ctx: &OperationContext,
185 path: &str,
186 args: OpRestore,
187 ) -> Result<RpRestore> {
188 self.inner.restore(ctx, path, args).await
189 }
190
191 async fn presign(
192 &self,
193 ctx: &OperationContext,
194 path: &str,
195 args: OpPresign,
196 ) -> Result<RpPresign> {
197 self.inner.presign(ctx, path, args).await
198 }
199}
200
201#[doc(hidden)]
202pub struct ChaosReader<R> {
203 inner: R,
204 rng: Arc<Mutex<StdRng>>,
205
206 error_ratio: f64,
207}
208
209impl<R> ChaosReader<R> {
210 fn new(inner: R, rng: Arc<Mutex<StdRng>>, error_ratio: f64) -> Self {
211 Self {
212 inner,
213 rng,
214 error_ratio,
215 }
216 }
217
218 fn i_feel_lucky(&self) -> bool {
221 let point: u32 = self.rng.lock().unwrap().random_range(0..100);
222 point >= (self.error_ratio * 100.0) as u32
223 }
224
225 fn unexpected_eof() -> Error {
226 Error::new(ErrorKind::Unexpected, "I am your chaos!")
227 .with_operation("chaos")
228 .set_temporary()
229 }
230}
231
232impl<R: oio::ReadStream> oio::ReadStream for ChaosReader<R> {
233 async fn read(&mut self) -> Result<Buffer> {
234 if self.i_feel_lucky() {
235 self.inner.read().await
236 } else {
237 Err(Self::unexpected_eof())
238 }
239 }
240}
241
242impl<R: oio::Read> oio::Read for ChaosReader<R> {
243 async fn open(&self, range: BytesRange) -> Result<(RpRead, Box<dyn oio::ReadStreamDyn>)> {
244 if self.i_feel_lucky() {
245 let (rp, stream) = self.inner.open(range).await?;
246 Ok((
247 rp,
248 Box::new(ChaosReader::new(stream, self.rng.clone(), self.error_ratio))
249 as Box<dyn oio::ReadStreamDyn>,
250 ))
251 } else {
252 Err(Self::unexpected_eof())
253 }
254 }
255
256 async fn read(&self, range: BytesRange) -> Result<(RpRead, Buffer)> {
257 if self.i_feel_lucky() {
258 self.inner.read(range).await
259 } else {
260 Err(Self::unexpected_eof())
261 }
262 }
263}