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  }