github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/perf/sawtooth_perf/src/batch_submit.rs (about) 1 /* 2 * Copyright 2017 Intel Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * ------------------------------------------------------------------------------ 16 */ 17 18 //! Tools for submitting batch lists of signed batches to Sawtooth endpoints 19 20 use std::cell::RefCell; 21 use std::error; 22 use std::fmt; 23 use std::io::Read; 24 use std::iter::Cycle; 25 use std::rc::Rc; 26 use std::sync::mpsc; 27 use std::sync::Arc; 28 use std::sync::Mutex; 29 use std::thread; 30 use std::time; 31 use std::vec::IntoIter; 32 33 use futures::{Future, Stream}; 34 use hyper::client::{Client, HttpConnector, Request}; 35 use hyper::header::{ContentLength, ContentType}; 36 use hyper::Method; 37 use protobuf; 38 use protobuf::Message; 39 use tokio_core::reactor::{Core, Interval}; 40 use tokio_timer; 41 42 use sawtooth_sdk::messages::batch::Batch; 43 use sawtooth_sdk::messages::batch::BatchList; 44 45 use batch_gen::{BatchResult, BatchingError}; 46 use batch_map::BatchMap; 47 use source::LengthDelimitedMessageSource; 48 use workload; 49 50 /// Populates a channel from a stream of length-delimited batches. 51 /// Starts one workload submitter of the appropriate type (http, zmq) 52 /// per target. Workload submitters consume from the channel at 53 /// the configured rate until the channel is exhausted. 54 pub fn submit_signed_batches( 55 reader: &mut Read, 56 target: String, 57 rate: usize, 58 ) -> Result<(), BatchReadingError> { 59 let (sender, receiver) = mpsc::channel(); 60 let receiver = Arc::new(Mutex::new(receiver)); 61 62 let submit_thread = thread::spawn(move || { 63 http_submitter(&target, rate as u64, &receiver); 64 }); 65 66 let mut feeder = BatchListFeeder::new(reader); 67 68 loop { 69 match feeder.next() { 70 Some(Ok(batch_list)) => { 71 sender.send(Some(batch_list)).unwrap(); 72 } 73 None => { 74 sender.send(None).unwrap(); 75 break; 76 } 77 Some(Err(err)) => return Err(err), 78 } 79 } 80 81 submit_thread.join().unwrap(); 82 83 Ok(()) 84 } 85 86 pub fn http_submitter( 87 target: &str, 88 rate: u64, 89 receiver: &Arc<Mutex<mpsc::Receiver<Option<BatchList>>>>, 90 ) { 91 let mut core = Core::new().unwrap(); 92 93 let client = Client::configure() 94 .connector(HttpConnector::new(1, &core.handle())) 95 .keep_alive(true) 96 .build(&core.handle()); 97 98 let timer = tokio_timer::wheel() 99 .tick_duration(time::Duration::new(0, 1_000_000)) 100 .build(); 101 102 // Define a target timeslice (how often to submit batches) based 103 // on number of nanoseconds in a second divided by rate 104 let timeslice = time::Duration::new(0, 1_000_000_000 / rate as u32); 105 106 let mut uri = target.to_string(); 107 uri.push_str("/batches"); 108 109 let mut count = 0; 110 let mut last_count = 0; 111 let mut last_time = time::Instant::now(); 112 let mut last_trace_time = time::Instant::now(); 113 114 while let Some(mut batch_list) = receiver.lock().unwrap().recv().unwrap() { 115 // Set the trace flag on a batch about once every 5 seconds 116 if (time::Instant::now() - last_trace_time).as_secs() > 5 { 117 batch_list.mut_batches()[0].trace = true; 118 last_trace_time = time::Instant::now(); 119 } 120 121 let bytes = batch_list.write_to_bytes().unwrap(); 122 123 let mut req = Request::new(Method::Post, uri.parse().unwrap()); 124 req.headers_mut().set(ContentType::octet_stream()); 125 req.headers_mut().set(ContentLength(bytes.len() as u64)); 126 req.set_body(bytes); 127 128 let work = client.request(req).and_then(|_| { 129 count += 1; 130 131 if count % rate == 0 { 132 let log_duration = time::Instant::now() - last_time; 133 let log_duration_flt = 134 log_duration.as_secs() as f64 + f64::from(log_duration.subsec_nanos()) * 1e-9; 135 136 println!( 137 "target: {} target rate: {} count: {} effective rate: {} per sec", 138 target, 139 rate, 140 count, 141 (count - last_count) as f64 / log_duration_flt 142 ); 143 144 last_count = count; 145 last_time = time::Instant::now(); 146 } 147 148 Ok(()) 149 }); 150 151 let request_time = time::Instant::now(); 152 core.run(work).unwrap(); 153 let runtime = time::Instant::now() - request_time; 154 155 if let Some(sleep_duration) = timeslice.checked_sub(runtime) { 156 let sleep = timer.sleep(sleep_duration); 157 sleep.wait().unwrap(); 158 } 159 } 160 } 161 162 /// Run a continuous load of the BatchLists that are generated by BatchListIter. 163 pub fn run_workload( 164 batch_list_iter: &mut Iterator<Item = BatchListResult>, 165 time_to_wait: u32, 166 update_time: u32, 167 targets: Vec<String>, 168 basic_auth: &Option<String>, 169 ) -> Result<(), workload::WorkloadError> { 170 let mut core = Core::new().unwrap(); 171 let handle = core.handle(); 172 let client = Rc::new(Client::configure().build(&handle)); 173 let counter = Rc::new(workload::HTTPRequestCounter::new()); 174 175 let mut urls: Cycle<IntoIter<String>> = targets.into_iter().cycle(); 176 177 let batch_map = Rc::new(RefCell::new(BatchMap::new())); 178 let batch_map_clone = Rc::clone(&batch_map); 179 180 let batches = Rc::new(RefCell::new(Vec::new())); 181 let batches_clone = Rc::clone(&batches); 182 183 let interval = Interval::new(time::Duration::new(0, time_to_wait), &handle).unwrap(); 184 let mut log_time = time::Instant::now(); 185 let stream = interval 186 .map_err(workload::WorkloadError::from) 187 .map(|_: ()| -> Result<(), workload::WorkloadError> { 188 let counter_clone = Rc::clone(&counter); 189 workload::log(&counter_clone, &mut log_time, update_time) 190 }) 191 .map(move |_| -> Result<BatchList, workload::WorkloadError> { 192 let batch_map = Rc::clone(&batch_map_clone); 193 let batches_clone = Rc::clone(&batches_clone); 194 workload::get_next_batchlist(batch_list_iter, &batch_map, &batches_clone) 195 }) 196 .map(|batch_list: Result<BatchList, workload::WorkloadError>| { 197 let basic_auth_c = basic_auth.clone(); 198 let urls_c = &mut urls; 199 workload::form_request_from_batchlist(urls_c, batch_list, &basic_auth_c) 200 }) 201 .map_err(workload::WorkloadError::from) 202 .and_then( 203 |req: Result<(Request, Option<String>), workload::WorkloadError>| { 204 let handle_clone = handle.clone(); 205 let client_clone = Rc::clone(&client); 206 let counter_clone = Rc::clone(&counter); 207 let batches_clone = Rc::clone(&batches); 208 workload::make_request( 209 &client_clone, 210 &handle_clone, 211 counter_clone, 212 Rc::clone(&batch_map), 213 batches_clone, 214 req, 215 ) 216 }, 217 ) 218 .for_each(|_| Ok(())); 219 220 core.run(stream) 221 } 222 223 type BatchSource<'a> = LengthDelimitedMessageSource<'a, Batch>; 224 225 /// Errors that may occur during the reading of batches. 226 #[derive(Debug)] 227 pub enum BatchReadingError { 228 MessageError(protobuf::ProtobufError), 229 BatchingError(BatchingError), 230 UnknownError, 231 } 232 233 impl From<protobuf::ProtobufError> for BatchReadingError { 234 fn from(err: protobuf::ProtobufError) -> Self { 235 BatchReadingError::MessageError(err) 236 } 237 } 238 239 impl fmt::Display for BatchReadingError { 240 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 241 match *self { 242 BatchReadingError::MessageError(ref err) => { 243 write!(f, "Error occurred reading messages: {}", err) 244 } 245 BatchReadingError::BatchingError(ref err) => { 246 write!(f, "Error creating the batch: {}", err) 247 } 248 BatchReadingError::UnknownError => write!(f, "There was an unknown batching error."), 249 } 250 } 251 } 252 253 impl error::Error for BatchReadingError { 254 fn description(&self) -> &str { 255 match *self { 256 BatchReadingError::MessageError(ref err) => err.description(), 257 BatchReadingError::BatchingError(ref err) => err.description(), 258 BatchReadingError::UnknownError => "There was an unknown batch error.", 259 } 260 } 261 262 fn cause(&self) -> Option<&error::Error> { 263 match *self { 264 BatchReadingError::MessageError(ref err) => Some(err), 265 BatchReadingError::BatchingError(ref err) => Some(err), 266 BatchReadingError::UnknownError => Some(&BatchReadingError::UnknownError), 267 } 268 } 269 } 270 271 /// Produces signed batches from a length-delimited source of Transactions. 272 pub struct BatchListFeeder<'a> { 273 batch_source: BatchSource<'a>, 274 } 275 276 /// Resulting BatchList or error. 277 pub type BatchListResult = Result<BatchList, BatchReadingError>; 278 279 impl<'a> BatchListFeeder<'a> { 280 /// Creates a new `BatchListFeeder` with a given Batch source 281 pub fn new(source: &'a mut Read) -> Self { 282 let batch_source = LengthDelimitedMessageSource::new(source); 283 BatchListFeeder { batch_source } 284 } 285 } 286 287 impl<'a> Iterator for BatchListFeeder<'a> { 288 type Item = BatchListResult; 289 290 /// Gets the next Batch. 291 /// `Ok(None)` indicates that the underlying source has been consumed. 292 fn next(&mut self) -> Option<Self::Item> { 293 let batches = match self.batch_source.next(1) { 294 Ok(batches) => batches, 295 Err(err) => return Some(Err(BatchReadingError::MessageError(err))), 296 }; 297 298 if batches.is_empty() { 299 return None; 300 } 301 302 // Construct a BatchList out of the read batches 303 let mut batch_list = BatchList::new(); 304 batch_list.set_batches(protobuf::RepeatedField::from_vec(batches)); 305 306 Some(Ok(batch_list)) 307 } 308 } 309 310 pub struct InfiniteBatchListIterator<'a> { 311 batches: &'a mut Iterator<Item = BatchResult>, 312 } 313 314 impl<'a> InfiniteBatchListIterator<'a> { 315 pub fn new(batches: &'a mut Iterator<Item = BatchResult>) -> Self { 316 InfiniteBatchListIterator { batches: batches } 317 } 318 } 319 320 impl<'a> Iterator for InfiniteBatchListIterator<'a> { 321 type Item = BatchListResult; 322 323 fn next(&mut self) -> Option<BatchListResult> { 324 let batch = match self.batches.next() { 325 Some(Ok(batch)) => batch, 326 Some(Err(err)) => return Some(Err(BatchReadingError::BatchingError(err))), 327 None => return None, 328 }; 329 330 let batches = vec![batch]; 331 let mut batch_list = BatchList::new(); 332 batch_list.set_batches(protobuf::RepeatedField::from_vec(batches)); 333 Some(Ok(batch_list)) 334 } 335 }