<commit_before>use std::str;
use std::cell::RefCell;
use std::time::Instant;
use std::collections::BTreeMap;
use std::net::SocketAddr;
use mio::net::UdpSocket;
use std::io::{self,Write};
use sozu_command::proxy::{FilteredData,MetricsData};

mod network_drain;
mod local_drain;
mod writer;

use self::network_drain::NetworkDrain;
use self::local_drain::LocalDrain;

thread_local! {
  pub static METRICS: RefCell<Aggregator> = RefCell::new(Aggregator::new(String::from("sozu")));
}

#[derive(Debug,Clone,PartialEq)]
pub enum MetricData {
  Gauge(usize),
  GaugeAdd(i64),
  Count(i64),
  Time(usize),
}

impl MetricData {
  fn is_time(&self) -> bool {
    match self {
      &MetricData::Time(_) => true,
      _ => false,
    }
  }

  fn update(&mut self, key: &'static str, m: MetricData) -> bool {
    match (self, m) {
      (&mut MetricData::Gauge(ref mut v1), MetricData::Gauge(v2)) => {
        let changed = *v1 != v2;
        *v1 = v2;
        changed
      },
      (&mut MetricData::Gauge(ref mut v1), MetricData::GaugeAdd(v2)) => {
        debug_assert!(*v1 as i64 + v2 >= 0, "metric {} underflow: previous value: {}, adding: {}", key, v1, v2);
        let changed = v2 != 0;
        let res = *v1 as i64 + v2;
        *v1 = if res >= 0 {
          res as usize
        } else {
          error!("metric {} underflow: previous value: {}, adding: {}", key, v1, v2);
          0
        };

        changed
      },
      (&mut MetricData::Count(ref mut v1), MetricData::Count(v2)) => {
        let changed = v2 != 0;
        *v1 += v2;
        changed
      },
      (s,m) => panic!("tried to update metric {} of value {:?} with an incompatible metric: {:?}", key, s, m)
    }
  }
}

#[derive(Debug,Clone)]
pub struct StoredMetricData {
  last_sent: Instant,
  updated:   bool,
  data:      MetricData,
}

impl StoredMetricData {
  pub fn new(last_sent: Instant, data: MetricData) -> StoredMetricData {
    StoredMetricData {
      last_sent,
      updated: true,
      data: if let MetricData::GaugeAdd(v) = data {
        MetricData::Gauge(v as usize)
      } else { data }
    }
  }

  pub fn update(&mut self, key: &'static str, m: MetricData) {
    let updated = self.data.update(key, m);
    if ! self.updated {
      self.updated = updated;
    }
  }
}

pub fn setup<O: Into<String>>(metrics_host: &SocketAddr, origin: O, use_tagged_metrics: bool, prefix: Option<String>) {
  let metrics_socket = udp_bind();

  debug!("setting up metrics: local address = {:#?}", metrics_socket.local_addr());

  METRICS.with(|metrics| {
    if let Some(p) = prefix {
      (*metrics.borrow_mut()).set_up_prefix(p);
    }
    (*metrics.borrow_mut()).set_up_remote(metrics_socket, metrics_host.clone());
    (*metrics.borrow_mut()).set_up_origin(origin.into());
    (*metrics.borrow_mut()).set_up_tagged_metrics(use_tagged_metrics);
  });
}

pub trait Subscriber {
  fn receive_metric(&mut self, label: &'static str, app_id: Option<&str>, backend_id: Option<&str>, metric: MetricData);
}

pub struct Aggregator {
  prefix:  String,
  network: Option<NetworkDrain>,
  local:   LocalDrain,
}

impl Aggregator {
  pub fn new(prefix: String) -> Aggregator {
    Aggregator {
      prefix: prefix.clone(),
      network: None,
      local: LocalDrain::new(prefix),
    }
  }

  pub fn set_up_prefix(&mut self, prefix: String) {
    self.prefix = prefix;
  }

  pub fn set_up_remote(&mut self, socket: UdpSocket, addr: SocketAddr) {
    self.network = Some(NetworkDrain::new(self.prefix.clone(), socket, addr));
  }

  pub fn set_up_origin(&mut self, origin: String) {
    self.network.as_mut().map(|n| n.origin = origin);
  }

  pub fn set_up_tagged_metrics(&mut self, tagged: bool) {
    self.network.as_mut().map(|n| n.use_tagged_metrics = tagged);
  }

  pub fn socket(&self) -> Option<&UdpSocket> {
    self.network.as_ref().map(|n| &n.remote.get_ref().socket)
  }

  pub fn count_add(&mut self, key: &'static str, count_value: i64) {
    self.receive_metric(key, None, None, MetricData::Count(count_value));
  }

  pub fn set_gauge(&mut self, key: &'static str, gauge_value: usize) {
    self.receive_metric(key, None, None, MetricData::Gauge(gauge_value));
  }

  pub fn gauge_add(&mut self, key: &'static str, gauge_value: i64) {
    self.receive_metric(key, None, None, MetricData::GaugeAdd(gauge_value));
  }

  pub fn writable(&mut self) {
    if let Some(ref mut net) = self.network.as_mut() {
      net.writable();
    }
  }

  pub fn send_data(&mut self) {
    if let Some(ref mut net) = self.network.as_mut() {
      net.send_data();
    }
  }

  pub fn dump_metrics_data(&mut self) -> MetricsData {
    self.local.dump_metrics_data()
  }

  pub fn dump_process_data(&mut self) -> BTreeMap<String, FilteredData> {
    self.local.dump_process_data()
  }

  pub fn clear_local(&mut self) {
    self.local.clear();
  }
}

impl Subscriber for Aggregator {
  fn receive_metric(&mut self, label: &'static str, app_id: Option<&str>, backend_id: Option<&str>, metric: MetricData) {
    if let Some(ref mut net) = self.network.as_mut() {
      net.receive_metric(label, app_id, backend_id, metric.clone());
    }
    self.local.receive_metric(label, app_id, backend_id, metric.clone());
  }
}

#[derive(Debug,Clone,PartialEq)]
pub struct MetricLine {
  label:      &'static str,
  app_id:     Option<String>,
  backend_id: Option<String>,
  /// in milliseconds
  duration:   usize,
}

pub struct MetricSocket {
  pub addr:   SocketAddr,
  pub socket: UdpSocket,
}

impl Write for MetricSocket {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.socket.send_to(buf, &self.addr)
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

pub fn udp_bind() -> UdpSocket {
  UdpSocket::bind(&("0.0.0.0:0".parse().unwrap())).expect("could not parse address")
}

#[macro_export]
macro_rules! count (
  ($key:expr, $value: expr) => ({
    let v = $value;
    $crate::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).count_add($key, v);
    });
  })
);

#[macro_export]
macro_rules! incr (
  ($key:expr) => (count!($key, 1););
  ($key:expr, $app_id:expr, $backend_id:expr) => {
    use $crate::metrics::Subscriber;

    $crate::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).receive_metric($key, $app_id, $backend_id, $crate::metrics::MetricData::Count(1));
    });
  }
);

#[macro_export]
macro_rules! decr (
  ($key:expr) => (count!($key, -1);)
);

#[macro_export]
macro_rules! gauge (
  ($key:expr, $value: expr) => ({
    let v = $value;
    $crate::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).set_gauge($key, v);
    });
  })
);

#[macro_export]
macro_rules! gauge_add (
  ($key:expr, $value: expr) => ({
    let v = $value;
    $crate::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).gauge_add($key, v);
    });
  });
  ($key:expr, $value:expr, $app_id:expr, $backend_id:expr) => {
    use $crate::metrics::Subscriber;
    let v = $value;

    $crate::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).receive_metric($key, $app_id, $backend_id, $crate::metrics::MetricData::GaugeAdd(v));
    });
  }
);

#[macro_export]
macro_rules! time (
  ($key:expr, $value: expr) => {
    use $crate::metrics::{MetricData,Subscriber};
    let v = $value;
    $crate::metrics::METRICS.with(|metrics| {
      let ref mut m = *metrics.borrow_mut();

      m.receive_metric($key, None, None, MetricData::Time(v as usize));
    });
  };
  ($key:expr, $app_id:expr, $value: expr) => ({
    use $crate::metrics::{MetricData,Subscriber};
    let v = $value;
    $crate::metrics::METRICS.with(|metrics| {
      let ref mut m = *metrics.borrow_mut();
      let app: &str = $app_id;

      m.receive_metric($key, Some(app), None, MetricData::Time(v as usize));
    });
  })
);

#[macro_export]
macro_rules! record_backend_metrics (
  ($app_id:expr, $backend_id:expr, $response_time: expr, $backend_connection_time: expr, $bin: expr, $bout: expr) => {
    use $crate::metrics::{MetricData,Subscriber};
    $crate::metrics::METRICS.with(|metrics| {
      let ref mut m = *metrics.borrow_mut();
      let app_id: &str = $app_id.as_str();
      let backend_id: &str = $backend_id;

      m.receive_metric("bytes_in", Some(app_id), Some(backend_id), MetricData::Count($bin as i64));
      m.receive_metric("bytes_out", Some(app_id), Some(backend_id), MetricData::Count($bout as i64));
      m.receive_metric("response_time", Some(app_id), Some(backend_id), MetricData::Time($response_time as usize));
      if let Some(t) = $backend_connection_time {
        m.receive_metric("connection_time", Some(app_id), Some(backend_id), MetricData::Time(t.num_milliseconds() as usize));
      }
    });
  }
);

<commit_msg>if a gauge metric was removed, do not underflow when creating it again<commit_after>use std::str;
use std::cell::RefCell;
use std::time::Instant;
use std::collections::BTreeMap;
use std::net::SocketAddr;
use mio::net::UdpSocket;
use std::io::{self,Write};
use sozu_command::proxy::{FilteredData,MetricsData};

mod network_drain;
mod local_drain;
mod writer;

use self::network_drain::NetworkDrain;
use self::local_drain::LocalDrain;

thread_local! {
  pub static METRICS: RefCell<Aggregator> = RefCell::new(Aggregator::new(String::from("sozu")));
}

#[derive(Debug,Clone,PartialEq)]
pub enum MetricData {
  Gauge(usize),
  GaugeAdd(i64),
  Count(i64),
  Time(usize),
}

impl MetricData {
  fn is_time(&self) -> bool {
    match self {
      &MetricData::Time(_) => true,
      _ => false,
    }
  }

  fn update(&mut self, key: &'static str, m: MetricData) -> bool {
    match (self, m) {
      (&mut MetricData::Gauge(ref mut v1), MetricData::Gauge(v2)) => {
        let changed = *v1 != v2;
        *v1 = v2;
        changed
      },
      (&mut MetricData::Gauge(ref mut v1), MetricData::GaugeAdd(v2)) => {
        debug_assert!(*v1 as i64 + v2 >= 0, "metric {} underflow: previous value: {}, adding: {}", key, v1, v2);
        let changed = v2 != 0;
        let res = *v1 as i64 + v2;
        *v1 = if res >= 0 {
          res as usize
        } else {
          error!("metric {} underflow: previous value: {}, adding: {}", key, v1, v2);
          0
        };

        changed
      },
      (&mut MetricData::Count(ref mut v1), MetricData::Count(v2)) => {
        let changed = v2 != 0;
        *v1 += v2;
        changed
      },
      (s,m) => panic!("tried to update metric {} of value {:?} with an incompatible metric: {:?}", key, s, m)
    }
  }
}

#[derive(Debug,Clone)]
pub struct StoredMetricData {
  last_sent: Instant,
  updated:   bool,
  data:      MetricData,
}

impl StoredMetricData {
  pub fn new(last_sent: Instant, data: MetricData) -> StoredMetricData {
    StoredMetricData {
      last_sent,
      updated: true,
      data: if let MetricData::GaugeAdd(v) = data {
        if v >= 0 {
          MetricData::Gauge(v as usize)
        } else {
          MetricData::Gauge(0)
        }
      } else { data }
    }
  }

  pub fn update(&mut self, key: &'static str, m: MetricData) {
    let updated = self.data.update(key, m);
    if ! self.updated {
      self.updated = updated;
    }
  }
}

pub fn setup<O: Into<String>>(metrics_host: &SocketAddr, origin: O, use_tagged_metrics: bool, prefix: Option<String>) {
  let metrics_socket = udp_bind();

  debug!("setting up metrics: local address = {:#?}", metrics_socket.local_addr());

  METRICS.with(|metrics| {
    if let Some(p) = prefix {
      (*metrics.borrow_mut()).set_up_prefix(p);
    }
    (*metrics.borrow_mut()).set_up_remote(metrics_socket, metrics_host.clone());
    (*metrics.borrow_mut()).set_up_origin(origin.into());
    (*metrics.borrow_mut()).set_up_tagged_metrics(use_tagged_metrics);
  });
}

pub trait Subscriber {
  fn receive_metric(&mut self, label: &'static str, app_id: Option<&str>, backend_id: Option<&str>, metric: MetricData);
}

pub struct Aggregator {
  prefix:  String,
  network: Option<NetworkDrain>,
  local:   LocalDrain,
}

impl Aggregator {
  pub fn new(prefix: String) -> Aggregator {
    Aggregator {
      prefix: prefix.clone(),
      network: None,
      local: LocalDrain::new(prefix),
    }
  }

  pub fn set_up_prefix(&mut self, prefix: String) {
    self.prefix = prefix;
  }

  pub fn set_up_remote(&mut self, socket: UdpSocket, addr: SocketAddr) {
    self.network = Some(NetworkDrain::new(self.prefix.clone(), socket, addr));
  }

  pub fn set_up_origin(&mut self, origin: String) {
    self.network.as_mut().map(|n| n.origin = origin);
  }

  pub fn set_up_tagged_metrics(&mut self, tagged: bool) {
    self.network.as_mut().map(|n| n.use_tagged_metrics = tagged);
  }

  pub fn socket(&self) -> Option<&UdpSocket> {
    self.network.as_ref().map(|n| &n.remote.get_ref().socket)
  }

  pub fn count_add(&mut self, key: &'static str, count_value: i64) {
    self.receive_metric(key, None, None, MetricData::Count(count_value));
  }

  pub fn set_gauge(&mut self, key: &'static str, gauge_value: usize) {
    self.receive_metric(key, None, None, MetricData::Gauge(gauge_value));
  }

  pub fn gauge_add(&mut self, key: &'static str, gauge_value: i64) {
    self.receive_metric(key, None, None, MetricData::GaugeAdd(gauge_value));
  }

  pub fn writable(&mut self) {
    if let Some(ref mut net) = self.network.as_mut() {
      net.writable();
    }
  }

  pub fn send_data(&mut self) {
    if let Some(ref mut net) = self.network.as_mut() {
      net.send_data();
    }
  }

  pub fn dump_metrics_data(&mut self) -> MetricsData {
    self.local.dump_metrics_data()
  }

  pub fn dump_process_data(&mut self) -> BTreeMap<String, FilteredData> {
    self.local.dump_process_data()
  }

  pub fn clear_local(&mut self) {
    self.local.clear();
  }
}

impl Subscriber for Aggregator {
  fn receive_metric(&mut self, label: &'static str, app_id: Option<&str>, backend_id: Option<&str>, metric: MetricData) {
    if let Some(ref mut net) = self.network.as_mut() {
      net.receive_metric(label, app_id, backend_id, metric.clone());
    }
    self.local.receive_metric(label, app_id, backend_id, metric.clone());
  }
}

#[derive(Debug,Clone,PartialEq)]
pub struct MetricLine {
  label:      &'static str,
  app_id:     Option<String>,
  backend_id: Option<String>,
  /// in milliseconds
  duration:   usize,
}

pub struct MetricSocket {
  pub addr:   SocketAddr,
  pub socket: UdpSocket,
}

impl Write for MetricSocket {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.socket.send_to(buf, &self.addr)
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

pub fn udp_bind() -> UdpSocket {
  UdpSocket::bind(&("0.0.0.0:0".parse().unwrap())).expect("could not parse address")
}

#[macro_export]
macro_rules! count (
  ($key:expr, $value: expr) => ({
    let v = $value;
    $crate::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).count_add($key, v);
    });
  })
);

#[macro_export]
macro_rules! incr (
  ($key:expr) => (count!($key, 1););
  ($key:expr, $app_id:expr, $backend_id:expr) => {
    use $crate::metrics::Subscriber;

    $crate::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).receive_metric($key, $app_id, $backend_id, $crate::metrics::MetricData::Count(1));
    });
  }
);

#[macro_export]
macro_rules! decr (
  ($key:expr) => (count!($key, -1);)
);

#[macro_export]
macro_rules! gauge (
  ($key:expr, $value: expr) => ({
    let v = $value;
    $crate::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).set_gauge($key, v);
    });
  })
);

#[macro_export]
macro_rules! gauge_add (
  ($key:expr, $value: expr) => ({
    let v = $value;
    $crate::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).gauge_add($key, v);
    });
  });
  ($key:expr, $value:expr, $app_id:expr, $backend_id:expr) => {
    use $crate::metrics::Subscriber;
    let v = $value;

    $crate::metrics::METRICS.with(|metrics| {
      (*metrics.borrow_mut()).receive_metric($key, $app_id, $backend_id, $crate::metrics::MetricData::GaugeAdd(v));
    });
  }
);

#[macro_export]
macro_rules! time (
  ($key:expr, $value: expr) => {
    use $crate::metrics::{MetricData,Subscriber};
    let v = $value;
    $crate::metrics::METRICS.with(|metrics| {
      let ref mut m = *metrics.borrow_mut();

      m.receive_metric($key, None, None, MetricData::Time(v as usize));
    });
  };
  ($key:expr, $app_id:expr, $value: expr) => ({
    use $crate::metrics::{MetricData,Subscriber};
    let v = $value;
    $crate::metrics::METRICS.with(|metrics| {
      let ref mut m = *metrics.borrow_mut();
      let app: &str = $app_id;

      m.receive_metric($key, Some(app), None, MetricData::Time(v as usize));
    });
  })
);

#[macro_export]
macro_rules! record_backend_metrics (
  ($app_id:expr, $backend_id:expr, $response_time: expr, $backend_connection_time: expr, $bin: expr, $bout: expr) => {
    use $crate::metrics::{MetricData,Subscriber};
    $crate::metrics::METRICS.with(|metrics| {
      let ref mut m = *metrics.borrow_mut();
      let app_id: &str = $app_id.as_str();
      let backend_id: &str = $backend_id;

      m.receive_metric("bytes_in", Some(app_id), Some(backend_id), MetricData::Count($bin as i64));
      m.receive_metric("bytes_out", Some(app_id), Some(backend_id), MetricData::Count($bout as i64));
      m.receive_metric("response_time", Some(app_id), Some(backend_id), MetricData::Time($response_time as usize));
      if let Some(t) = $backend_connection_time {
        m.receive_metric("connection_time", Some(app_id), Some(backend_id), MetricData::Time(t.num_milliseconds() as usize));
      }
    });
  }
);

<|endoftext|>


<commit_before>use crate::error::{Error, Result};
use crate::gen::fs;
use crate::paths;
use std::io;
use std::path::Path;

pub(crate) fn write(path: impl AsRef<Path>, content: &[u8]) -> Result<()> {
    let path = path.as_ref();

    let mut create_dir_error = None;
    if fs::exists(path) {
        if let Ok(existing) = fs::read(path) {
            if existing == content {
                // Avoid bumping modified time with unchanged contents.
                return Ok(());
            }
        }
        best_effort_remove(path);
    } else {
        let parent = path.parent().unwrap();
        create_dir_error = fs::create_dir_all(parent).err();
    }

    match fs::write(path, content) {
        // As long as write succeeded, ignore any create_dir_all error.
        Ok(()) => Ok(()),
        // If create_dir_all and write both failed, prefer the first error.
        Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
    }
}

pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
    let original = original.as_ref();
    let link = link.as_ref();

    let mut create_dir_error = None;
    if fs::exists(link) {
        best_effort_remove(link);
    } else {
        let parent = link.parent().unwrap();
        create_dir_error = fs::create_dir_all(parent).err();
    }

    match paths::symlink_or_copy(original, link) {
        // As long as symlink_or_copy succeeded, ignore any create_dir_all error.
        Ok(()) => Ok(()),
        Err(err) => {
            if err.kind() == io::ErrorKind::AlreadyExists {
                // This is fine, a different simultaneous build script already
                // created the same link or copy. The cxx_build target directory
                // is laid out such that the same path never refers to two
                // different targets during the same multi-crate build, so if
                // some other build script already created the same path then we
                // know it refers to the identical target that the current build
                // script was trying to create.
                Ok(())
            } else {
                // If create_dir_all and symlink_or_copy both failed, prefer the
                // first error.
                Err(Error::Fs(create_dir_error.unwrap_or(err)))
            }
        }
    }
}

pub(crate) fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
    let original = original.as_ref();
    let link = link.as_ref();

    let mut create_dir_error = None;
    if fs::exists(link) {
        best_effort_remove(link);
    } else {
        let parent = link.parent().unwrap();
        create_dir_error = fs::create_dir_all(parent).err();
    }

    match fs::symlink_dir(original, link) {
        // As long as symlink_dir succeeded, ignore any create_dir_all error.
        Ok(()) => Ok(()),
        // If create_dir_all and symlink_dir both failed, prefer the first error.
        Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
    }
}

fn best_effort_remove(path: &Path) {
    use std::fs;

    let file_type = match if cfg!(windows) {
        // On Windows, the correct choice of remove_file vs remove_dir needs to
        // be used according to what the symlink *points to*. Trying to use
        // remove_file to remove a symlink which points to a directory fails
        // with "Access is denied".
        fs::metadata(path).or_else(|_| fs::symlink_metadata(path))
    } else {
        // On non-Windows, we check metadata not following symlinks. All
        // symlinks are removed using remove_file.
        fs::symlink_metadata(path)
    } {
        Ok(metadata) => metadata.file_type(),
        Err(_) => return,
    };

    if file_type.is_dir() {
        let _ = fs::remove_dir_all(path);
    } else {
        let _ = fs::remove_file(path);
    }
}
<commit_msg>Fix Windows "access is denied" removing a dangling symlink<commit_after>use crate::error::{Error, Result};
use crate::gen::fs;
use crate::paths;
use std::io;
use std::path::Path;

pub(crate) fn write(path: impl AsRef<Path>, content: &[u8]) -> Result<()> {
    let path = path.as_ref();

    let mut create_dir_error = None;
    if fs::exists(path) {
        if let Ok(existing) = fs::read(path) {
            if existing == content {
                // Avoid bumping modified time with unchanged contents.
                return Ok(());
            }
        }
        best_effort_remove(path);
    } else {
        let parent = path.parent().unwrap();
        create_dir_error = fs::create_dir_all(parent).err();
    }

    match fs::write(path, content) {
        // As long as write succeeded, ignore any create_dir_all error.
        Ok(()) => Ok(()),
        // If create_dir_all and write both failed, prefer the first error.
        Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
    }
}

pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
    let original = original.as_ref();
    let link = link.as_ref();

    let mut create_dir_error = None;
    if fs::exists(link) {
        best_effort_remove(link);
    } else {
        let parent = link.parent().unwrap();
        create_dir_error = fs::create_dir_all(parent).err();
    }

    match paths::symlink_or_copy(original, link) {
        // As long as symlink_or_copy succeeded, ignore any create_dir_all error.
        Ok(()) => Ok(()),
        Err(err) => {
            if err.kind() == io::ErrorKind::AlreadyExists {
                // This is fine, a different simultaneous build script already
                // created the same link or copy. The cxx_build target directory
                // is laid out such that the same path never refers to two
                // different targets during the same multi-crate build, so if
                // some other build script already created the same path then we
                // know it refers to the identical target that the current build
                // script was trying to create.
                Ok(())
            } else {
                // If create_dir_all and symlink_or_copy both failed, prefer the
                // first error.
                Err(Error::Fs(create_dir_error.unwrap_or(err)))
            }
        }
    }
}

pub(crate) fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
    let original = original.as_ref();
    let link = link.as_ref();

    let mut create_dir_error = None;
    if fs::exists(link) {
        best_effort_remove(link);
    } else {
        let parent = link.parent().unwrap();
        create_dir_error = fs::create_dir_all(parent).err();
    }

    match fs::symlink_dir(original, link) {
        // As long as symlink_dir succeeded, ignore any create_dir_all error.
        Ok(()) => Ok(()),
        // If create_dir_all and symlink_dir both failed, prefer the first error.
        Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
    }
}

fn best_effort_remove(path: &Path) {
    use std::fs;

    if cfg!(windows) {
        // On Windows, the correct choice of remove_file vs remove_dir needs to
        // be used according to what the symlink *points to*. Trying to use
        // remove_file to remove a symlink which points to a directory fails
        // with "Access is denied".
        if let Ok(metadata) = fs::metadata(path) {
            if metadata.is_dir() {
                let _ = fs::remove_dir_all(path);
            } else {
                let _ = fs::remove_file(path);
            }
        } else if fs::symlink_metadata(path).is_ok() {
            // The symlink might exist but be dangling, in which case there is
            // no standard way to determine what "kind" of symlink it is. Try
            // deleting both ways.
            if fs::remove_dir_all(path).is_err() {
                let _ = fs::remove_file(path);
            }
        }
    } else {
        // On non-Windows, we check metadata not following symlinks. All
        // symlinks are removed using remove_file.
        if let Ok(metadata) = fs::symlink_metadata(path) {
            if metadata.is_dir() {
                let _ = fs::remove_dir_all(path);
            } else {
                let _ = fs::remove_file(path);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;

pub struct OtpDeviceState {
    otp: [u8; 0x100]
}

impl fmt::Debug for OtpDeviceState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "OtpDeviceState {{ }}")
    }
}

impl Default for OtpDeviceState {
    fn default() -> OtpDeviceState {
        OtpDeviceState {
            otp: [0; 0x100]
        }
    }
}

fn reg_otp_write(dev: &mut OtpDevice, buf_pos: usize, source: &[u8]) {
    dev._internal_state.otp[buf_pos .. buf_pos + source.len()].copy_from_slice(source);
}

fn reg_otp_read(dev: &mut OtpDevice, buf_pos: usize, dest: &mut [u8]) {
    let src_slice = &dev._internal_state.otp[buf_pos .. buf_pos + dest.len()];
    dest.clone_from_slice(src_slice);
}

iodevice!(OtpDevice, {
    internal_state: OtpDeviceState;
    regs: {}
    ranges: {
        0x000;0x100 => {
            read_effect = reg_otp_read;
            write_effect = reg_otp_write;
        }
    }
});<commit_msg>OTP: Read from dumped 3ds OTP file<commit_after>use std::env;
use std::fmt;
use std::fs::OpenOptions;
use std::io::Read;

pub struct OtpDeviceState {
    otp: [u8; 0x100]
}

impl fmt::Debug for OtpDeviceState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "OtpDeviceState {{ }}")
    }
}

impl Default for OtpDeviceState {
    fn default() -> OtpDeviceState {
        let filename = format!("{}/{}", env::var("HOME").unwrap(), "/.config/llama-otp.bin");
        let mut file = OpenOptions::new().read(true).write(true).open(&filename)
            .expect(&format!("Failed to open OTP file `{}`", filename));

        let mut otp = [0u8; 0x100];
        file.read_exact(&mut otp[..])
            .expect(&format!("Failed to read 256 bytes from OTP file `{}`", filename));

        OtpDeviceState {
            otp: otp
        }
    }
}

fn reg_otp_write(dev: &mut OtpDevice, buf_pos: usize, source: &[u8]) {
    dev._internal_state.otp[buf_pos .. buf_pos + source.len()].copy_from_slice(source);
}

fn reg_otp_read(dev: &mut OtpDevice, buf_pos: usize, dest: &mut [u8]) {
    let src_slice = &dev._internal_state.otp[buf_pos .. buf_pos + dest.len()];
    dest.clone_from_slice(src_slice);
}

iodevice!(OtpDevice, {
    internal_state: OtpDeviceState;
    regs: {}
    ranges: {
        0x000;0x100 => {
            read_effect = reg_otp_read;
            write_effect = reg_otp_write;
        }
    }
});<|endoftext|>


<commit_before>use std::f32;

use na::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3};
use ncollide3d::{
    query::Ray,
    shape::{Ball, ShapeHandle},
    world::{CollisionGroups, CollisionWorld, GeometricQueryType},
};

#[test]
fn interferences_with_ray() {
    let mut world = CollisionWorld::new(0.01);

    let shape = ShapeHandle::new(Ball::new(0.5f32));
    let groups = CollisionGroups::new();
    let query = GeometricQueryType::Contacts(0.0, 0.0);

    let tra = Translation3::new(1.0, 1.0, 1.0);
    let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::PI);
    let iso = Isometry3::from_parts(tra, rot);

    world.add(iso, shape.clone(), groups, query, ());

    let num_collision_objects = world.collision_objects().into_iter().collect::<Vec<_>>().len();
    assert!(
        num_collision_objects  == 1,
        format!("Expected 1 collision object, got {}", num_collision_objects),
    );

    let ray = Ray::new(Point3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0));
    let groups = CollisionGroups::new();
    let interferences = world.interferences_with_ray(&ray, &groups);

    let num_collisions = interferences.into_iter().collect::<Vec<_>>().len();
    assert!(
        num_collisions  == 1,
        format!("Expected 1 collision, got {}", num_collisions),
    );
}
<commit_msg>Improve test - toi_with_ray returns a positive<commit_after>use std::f32;

use na::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3};
use ncollide3d::{
    query::{Ray,RayCast},
    shape::{Ball, ShapeHandle},
    world::{CollisionGroups, CollisionWorld, GeometricQueryType},
};

#[test]
fn interferences_with_ray() {
    let mut world = CollisionWorld::new(0.01);

    let ball = Ball::new(0.5f32);
    let groups = CollisionGroups::new();
    let query = GeometricQueryType::Contacts(0.0, 0.0);

    let tra = Translation3::new(1.0, 1.0, 1.0);
    let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::PI);
    let iso = Isometry3::from_parts(tra, rot);

    let num_collision_objects = world.collision_objects().into_iter().collect::<Vec<_>>().len();
    assert!(
        num_collision_objects  == 1,
        format!("Expected 1 collision object, got {}", num_collision_objects),
    );

    let ray = Ray::new(Point3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0));

    assert!(ball.toi_with_ray(
        &iso,
        &ray,
        true,
    ).is_some());

    let shape = ShapeHandle::new(ball);
    world.add(iso, shape.clone(), groups, query, ());

    let interferences = world.interferences_with_ray(&ray, &groups);

    let num_collisions = interferences.into_iter().collect::<Vec<_>>().len();
    assert!(
        num_collisions  == 1,
        format!("Expected 1 collision, got {}", num_collisions),
    );
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::ToCss;

use euclid::length::Length;
use euclid::num::Zero;
use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::size::Size2D;

use std::default::Default;
use std::fmt;
use std::i32;
use std::ops::{Add, Sub, Neg, Mul, Div, Rem};

use rustc_serialize::{Encoder, Encodable};

// Units for use with euclid::length and euclid::scale_factor.

/// A normalized "pixel" at the default resolution for the display.
///
/// Like the CSS "px" unit, the exact physical size of this unit may vary between devices, but it
/// should approximate a device-independent reference length.  This unit corresponds to Android's
/// "density-independent pixel" (dip), Mac OS X's "point", and Windows "device-independent pixel."
///
/// The relationship between DevicePixel and ScreenPx is defined by the OS.  On most low-dpi
/// screens, one ScreenPx is equal to one DevicePixel.  But on high-density screens it can be
/// some larger number.  For example, by default on Apple "retina" displays, one ScreenPx equals
/// two DevicePixels.  On Android "MDPI" displays, one ScreenPx equals 1.5 device pixels.
///
/// The ratio between ScreenPx and DevicePixel for a given display be found by calling
/// `servo::windowing::WindowMethods::hidpi_factor`.
#[derive(Debug, Copy, Clone)]
pub enum ScreenPx {}

/// One CSS "px" in the coordinate system of the "initial viewport":
/// http://www.w3.org/TR/css-device-adapt/#initial-viewport
///
/// ViewportPx is equal to ScreenPx times a "page zoom" factor controlled by the user.  This is
/// the desktop-style "full page" zoom that enlarges content but then reflows the layout viewport
/// so it still exactly fits the visible area.
///
/// At the default zoom level of 100%, one PagePx is equal to one ScreenPx.  However, if the
/// document is zoomed in or out then this scale may be larger or smaller.
#[derive(RustcEncodable, Debug, Copy, Clone)]
pub enum ViewportPx {}

/// One CSS "px" in the root coordinate system for the content document.
///
/// PagePx is equal to ViewportPx multiplied by a "viewport zoom" factor controlled by the user.
/// This is the mobile-style "pinch zoom" that enlarges content without reflowing it.  When the
/// viewport zoom is not equal to 1.0, then the layout viewport is no longer the same physical size
/// as the viewable area.
#[derive(RustcEncodable, Debug, Copy, Clone)]
pub enum PagePx {}

// In summary, the hierarchy of pixel units and the factors to convert from one to the next:
//
// DevicePixel
//   / hidpi_ratio => ScreenPx
//     / desktop_zoom => ViewportPx
//       / pinch_zoom => PagePx

// An Au is an "App Unit" and represents 1/60th of a CSS pixel.  It was
// originally proposed in 2002 as a standard unit of measure in Gecko.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.
//
// FIXME: Implement Au using Length and ScaleFactor instead of a custom type.
#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Eq, Ord, Deserialize, Serialize)]
pub struct Au(pub i32);

impl Default for Au {
    #[inline]
    fn default() -> Au {
        Au(0)
    }
}

impl Zero for Au {
    #[inline]
    fn zero() -> Au {
        Au(0)
    }
}

pub static ZERO_POINT: Point2D<Au> = Point2D {
    x: Au(0),
    y: Au(0),
};

pub static ZERO_RECT: Rect<Au> = Rect {
    origin: Point2D {
        x: Au(0),
        y: Au(0),
    },
    size: Size2D {
        width: Au(0),
        height: Au(0),
    }
};

pub static MAX_RECT: Rect<Au> = Rect {
    origin: Point2D {
        x: Au(i32::MIN / 2),
        y: Au(i32::MIN / 2),
    },
    size: Size2D {
        width: MAX_AU,
        height: MAX_AU,
    }
};

pub const MIN_AU: Au = Au(i32::MIN);
pub const MAX_AU: Au = Au(i32::MAX);

impl Encodable for Au {
    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
        e.emit_f64(self.to_f64_px())
    }
}

impl fmt::Debug for Au {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}px", self.to_f64_px())
    }
}

impl ToCss for Au {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        write!(dest, "{}px", self.to_f64_px())
    }
}

impl Add for Au {
    type Output = Au;

    #[inline]
    fn add(self, other: Au) -> Au {
        Au(self.0.wrapping_add(other.0))
    }
}

impl Sub for Au {
    type Output = Au;

    #[inline]
    fn sub(self, other: Au) -> Au {
        Au(self.0.wrapping_sub(other.0))
    }

}

impl Mul<i32> for Au {
    type Output = Au;

    #[inline]
    fn mul(self, other: i32) -> Au {
        Au(self.0.wrapping_mul(other))
    }
}

impl Div<i32> for Au {
    type Output = Au;

    #[inline]
    fn div(self, other: i32) -> Au {
        Au(self.0 / other)
    }
}

impl Rem<i32> for Au {
    type Output = Au;

    #[inline]
    fn rem(self, other: i32) -> Au {
        Au(self.0 % other)
    }
}

impl Neg for Au {
    type Output = Au;

    #[inline]
    fn neg(self) -> Au {
        Au(-self.0)
    }
}

impl Au {
    /// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs!
    #[inline]
    pub fn new(value: i32) -> Au {
        Au(value)
    }

    #[inline]
    pub fn scale_by(self, factor: f32) -> Au {
        Au(((self.0 as f32) * factor) as i32)
    }

    #[inline]
    pub fn from_px(px: i32) -> Au {
        Au((px * 60) as i32)
    }

    #[inline]
    pub fn from_page_px(px: Length<PagePx, f32>) -> Au {
        Au((px.get() * 60f32) as i32)
    }

    /// Rounds this app unit down to the pixel towards zero and returns it.
    #[inline]
    pub fn to_px(self) -> i32 {
        self.0 / 60
    }

    /// Rounds this app unit down to the previous (left or top) pixel and returns it.
    #[inline]
    pub fn to_prev_px(self) -> i32 {
        ((self.0 as f64) / 60f64).floor() as i32
    }

    /// Rounds this app unit up to the next (right or bottom) pixel and returns it.
    #[inline]
    pub fn to_next_px(self) -> i32 {
        ((self.0 as f64) / 60f64).ceil() as i32
    }

    #[inline]
    pub fn to_nearest_px(self) -> i32 {
        ((self.0 as f64) / 60f64).round() as i32
    }

    #[inline]
    pub fn to_f32_px(self) -> f32 {
        (self.0 as f32) / 60f32
    }

    #[inline]
    pub fn to_f64_px(self) -> f64 {
        (self.0 as f64) / 60f64
    }

    #[inline]
    pub fn to_snapped(self) -> Au {
        let res = self.0 % 60i32;
        return if res >= 30i32 { return Au(self.0 - res + 60i32) }
                       else { return Au(self.0 - res) };
    }

    #[inline]
    pub fn from_f32_px(px: f32) -> Au {
        Au((px * 60f32) as i32)
    }

    #[inline]
    pub fn from_pt(pt: f64) -> Au {
        Au::from_f64_px(pt_to_px(pt))
    }

    #[inline]
    pub fn from_f64_px(px: f64) -> Au {
        Au((px * 60.) as i32)
    }
}

// assumes 72 points per inch, and 96 px per inch
pub fn pt_to_px(pt: f64) -> f64 {
    pt / 72. * 96.
}

// assumes 72 points per inch, and 96 px per inch
pub fn px_to_pt(px: f64) -> f64 {
    px / 96. * 72.
}

/// Returns true if the rect contains the given point. Points on the top or left sides of the rect
/// are considered inside the rectangle, while points on the right or bottom sides of the rect are
/// not considered inside the rectangle.
pub fn rect_contains_point<T: PartialOrd + Add<T, Output=T>>(rect: Rect<T>, point: Point2D<T>) -> bool {
    point.x >= rect.origin.x && point.x < rect.origin.x + rect.size.width &&
        point.y >= rect.origin.y && point.y < rect.origin.y + rect.size.height
}

/// A helper function to convert a rect of `f32` pixels to a rect of app units.
pub fn f32_rect_to_au_rect(rect: Rect<f32>) -> Rect<Au> {
    Rect::new(Point2D::new(Au::from_f32_px(rect.origin.x), Au::from_f32_px(rect.origin.y)),
              Size2D::new(Au::from_f32_px(rect.size.width), Au::from_f32_px(rect.size.height)))
}

/// A helper function to convert a rect of `Au` pixels to a rect of f32 units.
pub fn au_rect_to_f32_rect(rect: Rect<Au>) -> Rect<f32> {
    Rect::new(Point2D::new(rect.origin.x.to_f32_px(), rect.origin.y.to_f32_px()),
              Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px()))
}
<commit_msg>util: Make the number of app units per pixel a constant instead of repeating the literal value everywhere.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::ToCss;

use euclid::length::Length;
use euclid::num::Zero;
use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::size::Size2D;

use std::default::Default;
use std::fmt;
use std::i32;
use std::ops::{Add, Sub, Neg, Mul, Div, Rem};

use rustc_serialize::{Encoder, Encodable};

// Units for use with euclid::length and euclid::scale_factor.

/// A normalized "pixel" at the default resolution for the display.
///
/// Like the CSS "px" unit, the exact physical size of this unit may vary between devices, but it
/// should approximate a device-independent reference length.  This unit corresponds to Android's
/// "density-independent pixel" (dip), Mac OS X's "point", and Windows "device-independent pixel."
///
/// The relationship between DevicePixel and ScreenPx is defined by the OS.  On most low-dpi
/// screens, one ScreenPx is equal to one DevicePixel.  But on high-density screens it can be
/// some larger number.  For example, by default on Apple "retina" displays, one ScreenPx equals
/// two DevicePixels.  On Android "MDPI" displays, one ScreenPx equals 1.5 device pixels.
///
/// The ratio between ScreenPx and DevicePixel for a given display be found by calling
/// `servo::windowing::WindowMethods::hidpi_factor`.
#[derive(Debug, Copy, Clone)]
pub enum ScreenPx {}

/// One CSS "px" in the coordinate system of the "initial viewport":
/// http://www.w3.org/TR/css-device-adapt/#initial-viewport
///
/// ViewportPx is equal to ScreenPx times a "page zoom" factor controlled by the user.  This is
/// the desktop-style "full page" zoom that enlarges content but then reflows the layout viewport
/// so it still exactly fits the visible area.
///
/// At the default zoom level of 100%, one PagePx is equal to one ScreenPx.  However, if the
/// document is zoomed in or out then this scale may be larger or smaller.
#[derive(RustcEncodable, Debug, Copy, Clone)]
pub enum ViewportPx {}

/// One CSS "px" in the root coordinate system for the content document.
///
/// PagePx is equal to ViewportPx multiplied by a "viewport zoom" factor controlled by the user.
/// This is the mobile-style "pinch zoom" that enlarges content without reflowing it.  When the
/// viewport zoom is not equal to 1.0, then the layout viewport is no longer the same physical size
/// as the viewable area.
#[derive(RustcEncodable, Debug, Copy, Clone)]
pub enum PagePx {}

/// The number of app units in a pixel.
pub const AU_PER_PX: i32 = 60;

// In summary, the hierarchy of pixel units and the factors to convert from one to the next:
//
// DevicePixel
//   / hidpi_ratio => ScreenPx
//     / desktop_zoom => ViewportPx
//       / pinch_zoom => PagePx

// An Au is an "App Unit" and represents 1/60th of a CSS pixel.  It was
// originally proposed in 2002 as a standard unit of measure in Gecko.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.
//
// FIXME: Implement Au using Length and ScaleFactor instead of a custom type.
#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Eq, Ord, Deserialize, Serialize)]
pub struct Au(pub i32);

impl Default for Au {
    #[inline]
    fn default() -> Au {
        Au(0)
    }
}

impl Zero for Au {
    #[inline]
    fn zero() -> Au {
        Au(0)
    }
}

pub static ZERO_POINT: Point2D<Au> = Point2D {
    x: Au(0),
    y: Au(0),
};

pub static ZERO_RECT: Rect<Au> = Rect {
    origin: Point2D {
        x: Au(0),
        y: Au(0),
    },
    size: Size2D {
        width: Au(0),
        height: Au(0),
    }
};

pub static MAX_RECT: Rect<Au> = Rect {
    origin: Point2D {
        x: Au(i32::MIN / 2),
        y: Au(i32::MIN / 2),
    },
    size: Size2D {
        width: MAX_AU,
        height: MAX_AU,
    }
};

pub const MIN_AU: Au = Au(i32::MIN);
pub const MAX_AU: Au = Au(i32::MAX);

impl Encodable for Au {
    fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
        e.emit_f64(self.to_f64_px())
    }
}

impl fmt::Debug for Au {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}px", self.to_f64_px())
    }
}

impl ToCss for Au {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        write!(dest, "{}px", self.to_f64_px())
    }
}

impl Add for Au {
    type Output = Au;

    #[inline]
    fn add(self, other: Au) -> Au {
        Au(self.0.wrapping_add(other.0))
    }
}

impl Sub for Au {
    type Output = Au;

    #[inline]
    fn sub(self, other: Au) -> Au {
        Au(self.0.wrapping_sub(other.0))
    }

}

impl Mul<i32> for Au {
    type Output = Au;

    #[inline]
    fn mul(self, other: i32) -> Au {
        Au(self.0.wrapping_mul(other))
    }
}

impl Div<i32> for Au {
    type Output = Au;

    #[inline]
    fn div(self, other: i32) -> Au {
        Au(self.0 / other)
    }
}

impl Rem<i32> for Au {
    type Output = Au;

    #[inline]
    fn rem(self, other: i32) -> Au {
        Au(self.0 % other)
    }
}

impl Neg for Au {
    type Output = Au;

    #[inline]
    fn neg(self) -> Au {
        Au(-self.0)
    }
}

impl Au {
    /// FIXME(pcwalton): Workaround for lack of cross crate inlining of newtype structs!
    #[inline]
    pub fn new(value: i32) -> Au {
        Au(value)
    }

    #[inline]
    pub fn scale_by(self, factor: f32) -> Au {
        Au(((self.0 as f32) * factor) as i32)
    }

    #[inline]
    pub fn from_px(px: i32) -> Au {
        Au((px * AU_PER_PX) as i32)
    }

    #[inline]
    pub fn from_page_px(px: Length<PagePx, f32>) -> Au {
        Au((px.get() * (AU_PER_PX as f32)) as i32)
    }

    /// Rounds this app unit down to the pixel towards zero and returns it.
    #[inline]
    pub fn to_px(self) -> i32 {
        self.0 / AU_PER_PX
    }

    /// Rounds this app unit down to the previous (left or top) pixel and returns it.
    #[inline]
    pub fn to_prev_px(self) -> i32 {
        ((self.0 as f64) / (AU_PER_PX as f64)).floor() as i32
    }

    /// Rounds this app unit up to the next (right or bottom) pixel and returns it.
    #[inline]
    pub fn to_next_px(self) -> i32 {
        ((self.0 as f64) / (AU_PER_PX as f64)).ceil() as i32
    }

    #[inline]
    pub fn to_nearest_px(self) -> i32 {
        ((self.0 as f64) / (AU_PER_PX as f64)).round() as i32
    }

    #[inline]
    pub fn to_f32_px(self) -> f32 {
        (self.0 as f32) / (AU_PER_PX as f32)
    }

    #[inline]
    pub fn to_f64_px(self) -> f64 {
        (self.0 as f64) / (AU_PER_PX as f64)
    }

    #[inline]
    pub fn to_snapped(self) -> Au {
        let res = self.0 % AU_PER_PX;
        return if res >= 30i32 { return Au(self.0 - res + AU_PER_PX) }
                       else { return Au(self.0 - res) };
    }

    #[inline]
    pub fn from_f32_px(px: f32) -> Au {
        Au((px * (AU_PER_PX as f32)) as i32)
    }

    #[inline]
    pub fn from_pt(pt: f64) -> Au {
        Au::from_f64_px(pt_to_px(pt))
    }

    #[inline]
    pub fn from_f64_px(px: f64) -> Au {
        Au((px * (AU_PER_PX as f64)) as i32)
    }
}

// assumes 72 points per inch, and 96 px per inch
pub fn pt_to_px(pt: f64) -> f64 {
    pt / 72. * 96.
}

// assumes 72 points per inch, and 96 px per inch
pub fn px_to_pt(px: f64) -> f64 {
    px / 96. * 72.
}

/// Returns true if the rect contains the given point. Points on the top or left sides of the rect
/// are considered inside the rectangle, while points on the right or bottom sides of the rect are
/// not considered inside the rectangle.
pub fn rect_contains_point<T: PartialOrd + Add<T, Output=T>>(rect: Rect<T>, point: Point2D<T>) -> bool {
    point.x >= rect.origin.x && point.x < rect.origin.x + rect.size.width &&
        point.y >= rect.origin.y && point.y < rect.origin.y + rect.size.height
}

/// A helper function to convert a rect of `f32` pixels to a rect of app units.
pub fn f32_rect_to_au_rect(rect: Rect<f32>) -> Rect<Au> {
    Rect::new(Point2D::new(Au::from_f32_px(rect.origin.x), Au::from_f32_px(rect.origin.y)),
              Size2D::new(Au::from_f32_px(rect.size.width), Au::from_f32_px(rect.size.height)))
}

/// A helper function to convert a rect of `Au` pixels to a rect of f32 units.
pub fn au_rect_to_f32_rect(rect: Rect<Au>) -> Rect<f32> {
    Rect::new(Point2D::new(rect.origin.x.to_f32_px(), rect.origin.y.to_f32_px()),
              Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px()))
}
<|endoftext|>


<commit_before>use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors};
use rustc_index::vec::{Idx, IndexVec};

#[cfg(test)]
mod tests;

pub struct VecGraph<N: Idx> {
    /// Maps from a given node to an index where the set of successors
    /// for that node starts. The index indexes into the `edges`
    /// vector. To find the range for a given node, we look up the
    /// start for that node and then the start for the next node
    /// (i.e., with an index 1 higher) and get the range between the
    /// two. This vector always has an extra entry so that this works
    /// even for the max element.
    node_starts: IndexVec<N, usize>,

    edge_targets: Vec<N>,
}

impl<N: Idx> VecGraph<N> {
    pub fn new(num_nodes: usize, mut edge_pairs: Vec<(N, N)>) -> Self {
        // Sort the edges by the source -- this is important.
        edge_pairs.sort();

        let num_edges = edge_pairs.len();

        // Store the *target* of each edge into `edge_targets`.
        let edge_targets: Vec<N> = edge_pairs.iter().map(|&(_, target)| target).collect();

        // Create the *edge starts* array. We are iterating over over
        // the (sorted) edge pairs. We maintain the invariant that the
        // length of the `node_starts` arary is enough to store the
        // current source node -- so when we see that the source node
        // for an edge is greater than the current length, we grow the
        // edge-starts array by just enough.
        let mut node_starts = IndexVec::with_capacity(num_edges);
        for (index, &(source, _)) in edge_pairs.iter().enumerate() {
            // If we have a list like `[(0, x), (2, y)]`:
            //
            // - Start out with `node_starts` of `[]`
            // - Iterate to `(0, x)` at index 0:
            //   - Push one entry because `node_starts.len()` (0) is <= the source (0)
            //   - Leaving us with `node_starts` of `[0]`
            // - Iterate to `(2, y)` at index 1:
            //   - Push one entry because `node_starts.len()` (1) is <= the source (2)
            //   - Push one entry because `node_starts.len()` (2) is <= the source (2)
            //   - Leaving us with `node_starts` of `[0, 1, 1]`
            // - Loop terminates
            while node_starts.len() <= source.index() {
                node_starts.push(index);
            }
        }

        // Pad out the `node_starts` array so that it has `num_nodes +
        // 1` entries. Continuing our example above, if `num_nodes` is
        // be `3`, we would push one more index: `[0, 1, 1, 2]`.
        //
        // Interpretation of that vector:
        //
        // [0, 1, 1, 2]
        //        ---- range for N=2
        //     ---- range for N=1
        //  ---- range for N=0
        while node_starts.len() <= num_nodes {
            node_starts.push(edge_targets.len());
        }

        assert_eq!(node_starts.len(), num_nodes + 1);

        Self { node_starts, edge_targets }
    }

    /// Gets the successors for `source` as a slice.
    pub fn successors(&self, source: N) -> &[N] {
        let start_index = self.node_starts[source];
        let end_index = self.node_starts[source.plus(1)];
        &self.edge_targets[start_index..end_index]
    }
}

impl<N: Idx> DirectedGraph for VecGraph<N> {
    type Node = N;
}

impl<N: Idx> WithNumNodes for VecGraph<N> {
    fn num_nodes(&self) -> usize {
        self.node_starts.len() - 1
    }
}

impl<N: Idx> WithNumEdges for VecGraph<N> {
    fn num_edges(&self) -> usize {
        self.edge_targets.len()
    }
}

impl<N: Idx> GraphSuccessors<'graph> for VecGraph<N> {
    type Item = N;

    type Iter = std::iter::Cloned<std::slice::Iter<'graph, N>>;
}

impl<N: Idx> WithSuccessors for VecGraph<N> {
    fn successors(&self, node: N) -> <Self as GraphSuccessors<'_>>::Iter {
        self.successors(node).iter().cloned()
    }
}
<commit_msg>Fix typo in vec_graph<commit_after>use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors};
use rustc_index::vec::{Idx, IndexVec};

#[cfg(test)]
mod tests;

pub struct VecGraph<N: Idx> {
    /// Maps from a given node to an index where the set of successors
    /// for that node starts. The index indexes into the `edges`
    /// vector. To find the range for a given node, we look up the
    /// start for that node and then the start for the next node
    /// (i.e., with an index 1 higher) and get the range between the
    /// two. This vector always has an extra entry so that this works
    /// even for the max element.
    node_starts: IndexVec<N, usize>,

    edge_targets: Vec<N>,
}

impl<N: Idx> VecGraph<N> {
    pub fn new(num_nodes: usize, mut edge_pairs: Vec<(N, N)>) -> Self {
        // Sort the edges by the source -- this is important.
        edge_pairs.sort();

        let num_edges = edge_pairs.len();

        // Store the *target* of each edge into `edge_targets`.
        let edge_targets: Vec<N> = edge_pairs.iter().map(|&(_, target)| target).collect();

        // Create the *edge starts* array. We are iterating over over
        // the (sorted) edge pairs. We maintain the invariant that the
        // length of the `node_starts` array is enough to store the
        // current source node -- so when we see that the source node
        // for an edge is greater than the current length, we grow the
        // edge-starts array by just enough.
        let mut node_starts = IndexVec::with_capacity(num_edges);
        for (index, &(source, _)) in edge_pairs.iter().enumerate() {
            // If we have a list like `[(0, x), (2, y)]`:
            //
            // - Start out with `node_starts` of `[]`
            // - Iterate to `(0, x)` at index 0:
            //   - Push one entry because `node_starts.len()` (0) is <= the source (0)
            //   - Leaving us with `node_starts` of `[0]`
            // - Iterate to `(2, y)` at index 1:
            //   - Push one entry because `node_starts.len()` (1) is <= the source (2)
            //   - Push one entry because `node_starts.len()` (2) is <= the source (2)
            //   - Leaving us with `node_starts` of `[0, 1, 1]`
            // - Loop terminates
            while node_starts.len() <= source.index() {
                node_starts.push(index);
            }
        }

        // Pad out the `node_starts` array so that it has `num_nodes +
        // 1` entries. Continuing our example above, if `num_nodes` is
        // be `3`, we would push one more index: `[0, 1, 1, 2]`.
        //
        // Interpretation of that vector:
        //
        // [0, 1, 1, 2]
        //        ---- range for N=2
        //     ---- range for N=1
        //  ---- range for N=0
        while node_starts.len() <= num_nodes {
            node_starts.push(edge_targets.len());
        }

        assert_eq!(node_starts.len(), num_nodes + 1);

        Self { node_starts, edge_targets }
    }

    /// Gets the successors for `source` as a slice.
    pub fn successors(&self, source: N) -> &[N] {
        let start_index = self.node_starts[source];
        let end_index = self.node_starts[source.plus(1)];
        &self.edge_targets[start_index..end_index]
    }
}

impl<N: Idx> DirectedGraph for VecGraph<N> {
    type Node = N;
}

impl<N: Idx> WithNumNodes for VecGraph<N> {
    fn num_nodes(&self) -> usize {
        self.node_starts.len() - 1
    }
}

impl<N: Idx> WithNumEdges for VecGraph<N> {
    fn num_edges(&self) -> usize {
        self.edge_targets.len()
    }
}

impl<N: Idx> GraphSuccessors<'graph> for VecGraph<N> {
    type Item = N;

    type Iter = std::iter::Cloned<std::slice::Iter<'graph, N>>;
}

impl<N: Idx> WithSuccessors for VecGraph<N> {
    fn successors(&self, node: N) -> <Self as GraphSuccessors<'_>>::Iter {
        self.successors(node).iter().cloned()
    }
}
<|endoftext|>


<commit_before>// Generic AArch64 target for bare-metal code - Floating point disabled
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.
//
// For example, `-C target-cpu=cortex-a53`.

use super::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};

pub fn target() -> Target {
    let opts = TargetOptions {
        abi: "softfloat".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        linker: Some("rust-lld".to_owned()),
        features: "-mmx,-sse,+soft-float".to_string(),
        executables: true,
        disable_redzone: true,
        panic_strategy: PanicStrategy::Abort,
        ..Default::default()
    };
    Target {
        llvm_target: "x86_64-unknown-none-elf".to_string(),
        pointer_width: 64,
        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128".to_string(),
        arch: "x86_64".to_string(),
        options: opts,
    }
}
<commit_msg>Fix code formatting.<commit_after>// Generic AArch64 target for bare-metal code - Floating point disabled
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.
//
// For example, `-C target-cpu=cortex-a53`.

use super::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};

pub fn target() -> Target {
    let opts = TargetOptions {
        abi: "softfloat".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        linker: Some("rust-lld".to_owned()),
        features: "-mmx,-sse,+soft-float".to_string(),
        executables: true,
        disable_redzone: true,
        panic_strategy: PanicStrategy::Abort,
        ..Default::default()
    };
    Target {
        llvm_target: "x86_64-unknown-none-elf".to_string(),
        pointer_width: 64,
        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
            .to_string(),
        arch: "x86_64".to_string(),
        options: opts,
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use crate::logging::{LogEntry, LogSchema};
use anyhow::Result;
use aptos_crypto::HashValue;
use aptos_infallible::RwLock;
use aptos_logger::prelude::*;
use aptos_state_view::StateViewId;
use aptos_types::{
    ledger_info::LedgerInfoWithSignatures, state_store::state_value::StateValue,
    transaction::Transaction,
};
use aptos_vm::VMExecutor;
use executor_types::{BlockExecutorTrait, Error, StateComputeResult};
use fail::fail_point;
use scratchpad::SparseMerkleTree;
use std::{marker::PhantomData, sync::Arc};
use storage_interface::{async_proof_fetcher::AsyncProofFetcher, proof_fetcher::ProofFetcher};

use crate::{
    components::{block_tree::BlockTree, chunk_output::ChunkOutput},
    metrics::{
        APTOS_EXECUTOR_COMMIT_BLOCKS_SECONDS, APTOS_EXECUTOR_EXECUTE_BLOCK_SECONDS,
        APTOS_EXECUTOR_SAVE_TRANSACTIONS_SECONDS, APTOS_EXECUTOR_TRANSACTIONS_SAVED,
        APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS,
    },
};
use storage_interface::DbReaderWriter;

pub struct BlockExecutor<V> {
    pub db: DbReaderWriter,
    inner: RwLock<Option<BlockExecutorInner<V>>>,
}

impl<V> BlockExecutor<V>
where
    V: VMExecutor,
{
    pub fn new(db: DbReaderWriter) -> Self {
        Self {
            db,
            inner: RwLock::new(None),
        }
    }

    pub fn root_smt(&self) -> SparseMerkleTree<StateValue> {
        self.inner
            .read()
            .as_ref()
            .expect("BlockExecutor is not reset")
            .root_smt()
    }

    fn maybe_initialize(&self) {
        if self.inner.read().is_none() {
            self.reset();
        }
    }
}

impl<V> BlockExecutorTrait for BlockExecutor<V>
where
    V: VMExecutor,
{
    fn committed_block_id(&self) -> HashValue {
        self.maybe_initialize();
        self.inner
            .read()
            .as_ref()
            .expect("BlockExecutor is not reset")
            .committed_block_id()
    }

    fn reset(&self) {
        *self.inner.write() = Some(BlockExecutorInner::new(self.db.clone()));
    }

    fn execute_block(
        &self,
        block: (HashValue, Vec<Transaction>),
        parent_block_id: HashValue,
    ) -> Result<StateComputeResult, Error> {
        self.maybe_initialize();
        self.inner
            .read()
            .as_ref()
            .expect("BlockExecutor is not reset")
            .execute_block(block, parent_block_id)
    }

    fn commit_blocks_ext(
        &self,
        block_ids: Vec<HashValue>,
        ledger_info_with_sigs: LedgerInfoWithSignatures,
        save_state_snapshots: bool,
    ) -> Result<(), Error> {
        self.inner
            .read()
            .as_ref()
            .expect("BlockExecutor is not reset")
            .commit_blocks_ext(block_ids, ledger_info_with_sigs, save_state_snapshots)
    }

    fn finish(&self) {
        *self.inner.write() = None;
    }
}

struct BlockExecutorInner<V> {
    db: DbReaderWriter,
    block_tree: BlockTree,
    proof_fetcher: Arc<dyn ProofFetcher>,
    phantom: PhantomData<V>,
}

impl<V> BlockExecutorInner<V>
where
    V: VMExecutor,
{
    pub fn new(db: DbReaderWriter) -> Self {
        let block_tree = BlockTree::new(&db.reader).expect("Block tree failed to init.");
        let proof_fetcher = Arc::new(AsyncProofFetcher::new(db.reader.clone()));
        Self {
            db,
            block_tree,
            proof_fetcher,
            phantom: PhantomData,
        }
    }

    fn root_smt(&self) -> SparseMerkleTree<StateValue> {
        self.block_tree
            .root_block()
            .output
            .result_view
            .state()
            .current
            .clone()
    }
}

impl<V> BlockExecutorInner<V>
where
    V: VMExecutor,
{
    fn committed_block_id(&self) -> HashValue {
        self.block_tree.root_block().id
    }

    fn execute_block(
        &self,
        block: (HashValue, Vec<Transaction>),
        parent_block_id: HashValue,
    ) -> Result<StateComputeResult, Error> {
        let (block_id, transactions) = block;
        let committed_block = self.block_tree.root_block();
        let mut block_vec = self
            .block_tree
            .get_blocks_opt(&[block_id, parent_block_id])?;
        let parent_block = block_vec
            .pop()
            .expect("Must exist.")
            .ok_or(Error::BlockNotFound(parent_block_id))?;
        let parent_output = &parent_block.output;
        let parent_view = &parent_output.result_view;
        let parent_accumulator = parent_view.txn_accumulator();

        if let Some(b) = block_vec.pop().expect("Must exist") {
            // this is a retry
            return Ok(b.output.as_state_compute_result(parent_accumulator));
        }

        let output = if parent_block_id != committed_block.id && parent_output.has_reconfiguration()
        {
            info!(
                LogSchema::new(LogEntry::BlockExecutor).block_id(block_id),
                "reconfig_descendant_block_received"
            );
            parent_output.reconfig_suffix()
        } else {
            info!(
                LogSchema::new(LogEntry::BlockExecutor).block_id(block_id),
                "execute_block"
            );
            let _timer = APTOS_EXECUTOR_EXECUTE_BLOCK_SECONDS.start_timer();
            let state_view = parent_view.verified_state_view(
                StateViewId::BlockExecution { block_id },
                Arc::clone(&self.db.reader),
                Arc::clone(&self.proof_fetcher),
            )?;

            let chunk_output = {
                let _timer = APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS.start_timer();
                fail_point!("executor::vm_execute_block", |_| {
                    Err(Error::from(anyhow::anyhow!(
                        "Injected error in vm_execute_block"
                    )))
                });
                ChunkOutput::by_transaction_execution::<V>(transactions, state_view)?
            };
            chunk_output.trace_log_transaction_status();

            let (output, _, _) = chunk_output.apply_to_ledger(parent_view)?;
            output
        };
        output.ensure_ends_with_state_checkpoint()?;

        let block = self
            .block_tree
            .add_block(parent_block_id, block_id, output)?;
        Ok(block.output.as_state_compute_result(parent_accumulator))
    }

    fn commit_blocks_ext(
        &self,
        block_ids: Vec<HashValue>,
        ledger_info_with_sigs: LedgerInfoWithSignatures,
        sync_commit: bool,
    ) -> Result<(), Error> {
        let _timer = APTOS_EXECUTOR_COMMIT_BLOCKS_SECONDS.start_timer();
        let committed_block = self.block_tree.root_block();
        if committed_block.num_persisted_transactions()
            == ledger_info_with_sigs.ledger_info().version() + 1
        {
            // a retry
            return Ok(());
        }

        let block_id_to_commit = ledger_info_with_sigs.ledger_info().consensus_block_id();
        info!(
            LogSchema::new(LogEntry::BlockExecutor).block_id(block_id_to_commit),
            "commit_block"
        );

        let blocks = self.block_tree.get_blocks(&block_ids)?;
        let txns_to_commit: Vec<_> = blocks
            .into_iter()
            .map(|block| block.output.transactions_to_commit())
            .collect::<Result<Vec<_>>>()?
            .into_iter()
            .flatten()
            .collect();
        let first_version = committed_block
            .output
            .result_view
            .txn_accumulator()
            .num_leaves();
        let to_commit = txns_to_commit.len();
        let target_version = ledger_info_with_sigs.ledger_info().version();
        if first_version + txns_to_commit.len() as u64 != target_version + 1 {
            return Err(Error::BadNumTxnsToCommit {
                first_version,
                to_commit,
                target_version,
            });
        }

        let _timer = APTOS_EXECUTOR_SAVE_TRANSACTIONS_SECONDS.start_timer();
        APTOS_EXECUTOR_TRANSACTIONS_SAVED.observe(to_commit as f64);

        fail_point!("executor::commit_blocks", |_| {
            Err(anyhow::anyhow!("Injected error in commit_blocks.").into())
        });
        let result_in_memory_state = self
            .block_tree
            .get_block(block_id_to_commit)?
            .output
            .result_view
            .state()
            .clone();
        self.db.writer.save_transactions(
            &txns_to_commit,
            first_version,
            committed_block.output.result_view.state().base_version,
            Some(&ledger_info_with_sigs),
            sync_commit,
            result_in_memory_state,
        )?;
        self.block_tree
            .prune(ledger_info_with_sigs.ledger_info())
            .expect("Failure pruning block tree.");

        Ok(())
    }
}
<commit_msg>[Execution] Do not reuse proof fetcher across multiple block executions. (#2353)<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use crate::logging::{LogEntry, LogSchema};
use anyhow::Result;
use aptos_crypto::HashValue;
use aptos_infallible::RwLock;
use aptos_logger::prelude::*;
use aptos_state_view::StateViewId;
use aptos_types::{
    ledger_info::LedgerInfoWithSignatures, state_store::state_value::StateValue,
    transaction::Transaction,
};
use aptos_vm::VMExecutor;
use executor_types::{BlockExecutorTrait, Error, StateComputeResult};
use fail::fail_point;
use scratchpad::SparseMerkleTree;
use std::{marker::PhantomData, sync::Arc};
use storage_interface::async_proof_fetcher::AsyncProofFetcher;

use crate::{
    components::{block_tree::BlockTree, chunk_output::ChunkOutput},
    metrics::{
        APTOS_EXECUTOR_COMMIT_BLOCKS_SECONDS, APTOS_EXECUTOR_EXECUTE_BLOCK_SECONDS,
        APTOS_EXECUTOR_SAVE_TRANSACTIONS_SECONDS, APTOS_EXECUTOR_TRANSACTIONS_SAVED,
        APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS,
    },
};
use storage_interface::DbReaderWriter;

pub struct BlockExecutor<V> {
    pub db: DbReaderWriter,
    inner: RwLock<Option<BlockExecutorInner<V>>>,
}

impl<V> BlockExecutor<V>
where
    V: VMExecutor,
{
    pub fn new(db: DbReaderWriter) -> Self {
        Self {
            db,
            inner: RwLock::new(None),
        }
    }

    pub fn root_smt(&self) -> SparseMerkleTree<StateValue> {
        self.inner
            .read()
            .as_ref()
            .expect("BlockExecutor is not reset")
            .root_smt()
    }

    fn maybe_initialize(&self) {
        if self.inner.read().is_none() {
            self.reset();
        }
    }
}

impl<V> BlockExecutorTrait for BlockExecutor<V>
where
    V: VMExecutor,
{
    fn committed_block_id(&self) -> HashValue {
        self.maybe_initialize();
        self.inner
            .read()
            .as_ref()
            .expect("BlockExecutor is not reset")
            .committed_block_id()
    }

    fn reset(&self) {
        *self.inner.write() = Some(BlockExecutorInner::new(self.db.clone()));
    }

    fn execute_block(
        &self,
        block: (HashValue, Vec<Transaction>),
        parent_block_id: HashValue,
    ) -> Result<StateComputeResult, Error> {
        self.maybe_initialize();
        self.inner
            .read()
            .as_ref()
            .expect("BlockExecutor is not reset")
            .execute_block(block, parent_block_id)
    }

    fn commit_blocks_ext(
        &self,
        block_ids: Vec<HashValue>,
        ledger_info_with_sigs: LedgerInfoWithSignatures,
        save_state_snapshots: bool,
    ) -> Result<(), Error> {
        self.inner
            .read()
            .as_ref()
            .expect("BlockExecutor is not reset")
            .commit_blocks_ext(block_ids, ledger_info_with_sigs, save_state_snapshots)
    }

    fn finish(&self) {
        *self.inner.write() = None;
    }
}

struct BlockExecutorInner<V> {
    db: DbReaderWriter,
    block_tree: BlockTree,
    phantom: PhantomData<V>,
}

impl<V> BlockExecutorInner<V>
where
    V: VMExecutor,
{
    pub fn new(db: DbReaderWriter) -> Self {
        let block_tree = BlockTree::new(&db.reader).expect("Block tree failed to init.");
        Self {
            db,
            block_tree,
            phantom: PhantomData,
        }
    }

    fn root_smt(&self) -> SparseMerkleTree<StateValue> {
        self.block_tree
            .root_block()
            .output
            .result_view
            .state()
            .current
            .clone()
    }
}

impl<V> BlockExecutorInner<V>
where
    V: VMExecutor,
{
    fn committed_block_id(&self) -> HashValue {
        self.block_tree.root_block().id
    }

    fn execute_block(
        &self,
        block: (HashValue, Vec<Transaction>),
        parent_block_id: HashValue,
    ) -> Result<StateComputeResult, Error> {
        let (block_id, transactions) = block;
        let committed_block = self.block_tree.root_block();
        let mut block_vec = self
            .block_tree
            .get_blocks_opt(&[block_id, parent_block_id])?;
        let parent_block = block_vec
            .pop()
            .expect("Must exist.")
            .ok_or(Error::BlockNotFound(parent_block_id))?;
        let parent_output = &parent_block.output;
        let parent_view = &parent_output.result_view;
        let parent_accumulator = parent_view.txn_accumulator();

        if let Some(b) = block_vec.pop().expect("Must exist") {
            // this is a retry
            return Ok(b.output.as_state_compute_result(parent_accumulator));
        }

        let output = if parent_block_id != committed_block.id && parent_output.has_reconfiguration()
        {
            info!(
                LogSchema::new(LogEntry::BlockExecutor).block_id(block_id),
                "reconfig_descendant_block_received"
            );
            parent_output.reconfig_suffix()
        } else {
            info!(
                LogSchema::new(LogEntry::BlockExecutor).block_id(block_id),
                "execute_block"
            );
            let _timer = APTOS_EXECUTOR_EXECUTE_BLOCK_SECONDS.start_timer();
            let state_view = parent_view.verified_state_view(
                StateViewId::BlockExecution { block_id },
                Arc::clone(&self.db.reader),
                Arc::new(AsyncProofFetcher::new(self.db.reader.clone())),
            )?;

            let chunk_output = {
                let _timer = APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS.start_timer();
                fail_point!("executor::vm_execute_block", |_| {
                    Err(Error::from(anyhow::anyhow!(
                        "Injected error in vm_execute_block"
                    )))
                });
                ChunkOutput::by_transaction_execution::<V>(transactions, state_view)?
            };
            chunk_output.trace_log_transaction_status();

            let (output, _, _) = chunk_output.apply_to_ledger(parent_view)?;
            output
        };
        output.ensure_ends_with_state_checkpoint()?;

        let block = self
            .block_tree
            .add_block(parent_block_id, block_id, output)?;
        Ok(block.output.as_state_compute_result(parent_accumulator))
    }

    fn commit_blocks_ext(
        &self,
        block_ids: Vec<HashValue>,
        ledger_info_with_sigs: LedgerInfoWithSignatures,
        sync_commit: bool,
    ) -> Result<(), Error> {
        let _timer = APTOS_EXECUTOR_COMMIT_BLOCKS_SECONDS.start_timer();
        let committed_block = self.block_tree.root_block();
        if committed_block.num_persisted_transactions()
            == ledger_info_with_sigs.ledger_info().version() + 1
        {
            // a retry
            return Ok(());
        }

        let block_id_to_commit = ledger_info_with_sigs.ledger_info().consensus_block_id();
        info!(
            LogSchema::new(LogEntry::BlockExecutor).block_id(block_id_to_commit),
            "commit_block"
        );

        let blocks = self.block_tree.get_blocks(&block_ids)?;
        let txns_to_commit: Vec<_> = blocks
            .into_iter()
            .map(|block| block.output.transactions_to_commit())
            .collect::<Result<Vec<_>>>()?
            .into_iter()
            .flatten()
            .collect();
        let first_version = committed_block
            .output
            .result_view
            .txn_accumulator()
            .num_leaves();
        let to_commit = txns_to_commit.len();
        let target_version = ledger_info_with_sigs.ledger_info().version();
        if first_version + txns_to_commit.len() as u64 != target_version + 1 {
            return Err(Error::BadNumTxnsToCommit {
                first_version,
                to_commit,
                target_version,
            });
        }

        let _timer = APTOS_EXECUTOR_SAVE_TRANSACTIONS_SECONDS.start_timer();
        APTOS_EXECUTOR_TRANSACTIONS_SAVED.observe(to_commit as f64);

        fail_point!("executor::commit_blocks", |_| {
            Err(anyhow::anyhow!("Injected error in commit_blocks.").into())
        });
        let result_in_memory_state = self
            .block_tree
            .get_block(block_id_to_commit)?
            .output
            .result_view
            .state()
            .clone();
        self.db.writer.save_transactions(
            &txns_to_commit,
            first_version,
            committed_block.output.result_view.state().base_version,
            Some(&ledger_info_with_sigs),
            sync_commit,
            result_in_memory_state,
        )?;
        self.block_tree
            .prune(ledger_info_with_sigs.ledger_info())
            .expect("Failure pruning block tree.");

        Ok(())
    }
}
<|endoftext|>