<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for Linux / Android
extern crate std;
extern crate libc;

use super::Error;
use super::utils::use_init;
use std::fs::File;
use std::io;
use std::io::Read;
use std::cell::RefCell;

enum RngSource {
    GetRandom,
    Device(File),
}

thread_local!(
    static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);

fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {
    let ret = unsafe {
        libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), 0)
    };
    if ret == -1 || ret != dest.len() as i64 {
        return Err(io::Error::last_os_error());
    }
    Ok(())
}

pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
    RNG_SOURCE.with(|f| {
        use_init(f,
        || {
            let s = if is_getrandom_available() {
                RngSource::GetRandom
            } else {
                // read one byte from "/dev/random" to ensure that
                // OS RNG has initialized
                File::open("/dev/random")?.read_exact(&mut [0u8; 1])?;
                RngSource::Device(File::open("/dev/urandom")?)
            };
            Ok(s)
        }, |f| {
            match f {
                RngSource::GetRandom => syscall_getrandom(dest),
                RngSource::Device(f) => f.read_exact(dest),
            }
        }).map_err(|_| Error::Unknown)
    })
}

fn is_getrandom_available() -> bool {
    use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
    use std::sync::{Once, ONCE_INIT};

    static CHECKER: Once = ONCE_INIT;
    static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

    CHECKER.call_once(|| {
        let mut buf: [u8; 0] = [];
        let available = match syscall_getrandom(&mut buf) {
            Ok(()) => true,
            Err(err) => err.raw_os_error() != Some(libc::ENOSYS),
        };
        AVAILABLE.store(available, Ordering::Relaxed);
    });

    AVAILABLE.load(Ordering::Relaxed)
}
<commit_msg>remove redundant extern crate<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation for Linux / Android
extern crate libc;

use super::Error;
use super::utils::use_init;
use std::fs::File;
use std::io;
use std::io::Read;
use std::cell::RefCell;

enum RngSource {
    GetRandom,
    Device(File),
}

thread_local!(
    static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
);

fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {
    let ret = unsafe {
        libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), 0)
    };
    if ret == -1 || ret != dest.len() as i64 {
        return Err(io::Error::last_os_error());
    }
    Ok(())
}

pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
    RNG_SOURCE.with(|f| {
        use_init(f,
        || {
            let s = if is_getrandom_available() {
                RngSource::GetRandom
            } else {
                // read one byte from "/dev/random" to ensure that
                // OS RNG has initialized
                File::open("/dev/random")?.read_exact(&mut [0u8; 1])?;
                RngSource::Device(File::open("/dev/urandom")?)
            };
            Ok(s)
        }, |f| {
            match f {
                RngSource::GetRandom => syscall_getrandom(dest),
                RngSource::Device(f) => f.read_exact(dest),
            }
        }).map_err(|_| Error::Unknown)
    })
}

fn is_getrandom_available() -> bool {
    use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
    use std::sync::{Once, ONCE_INIT};

    static CHECKER: Once = ONCE_INIT;
    static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

    CHECKER.call_once(|| {
        let mut buf: [u8; 0] = [];
        let available = match syscall_getrandom(&mut buf) {
            Ok(()) => true,
            Err(err) => err.raw_os_error() != Some(libc::ENOSYS),
        };
        AVAILABLE.store(available, Ordering::Relaxed);
    });

    AVAILABLE.load(Ordering::Relaxed)
}
<|endoftext|>


<commit_before>//! Statuses interface

use self::super::Github;
use rep::{Status, StatusReq};
use rustc_serialize::json;
use std::io::Result;

#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum State {
  pending, success, error, failure
}

/// interface for statuses assocaited with a repository
pub struct Statuses<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str
}

impl<'a> Statuses<'a> {
  pub fn new(github: &'a Github<'a>, owner: &'static str, repo: &'static str) -> Statuses<'a> {
    Statuses {
      github: github,
      owner: owner,
      repo: repo
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/statuses{}", self.owner, self.repo, more)
  }

  /// creates a new status for a target sha
  pub fn create(&self, sha: &'static str, status: &StatusReq) -> Result<Status> {
    let data = json::encode(&status).unwrap();
    let body = try!(
      self.github.post(
        &self.path(&format!("/{}", sha)),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Status>(&body).unwrap())
  }

  /// lists all statuses associated with a given git sha
  pub fn list(&self, sha: &'static str) -> Result<Vec<Status>> {
    let body = try!(
      self.github.get(
        &format!(
          "/repos/{}/{}/commits/{}/statuses", self.owner, self.repo, sha
        )
      )
    );
    Ok(json::decode::<Vec<Status>>(&body).unwrap())
  }

  /// list the combined statuses for a given git sha
  pub fn combined(&self, sha: &'static str) -> Result<String> {
    let body = try!(
      self.github.get(
        &format!(
          "/repos/{}/{}/commits/{}/status", self.owner, self.repo, sha
        )
      )
    );
    Ok(body)
//    Ok(json::decode::<Vec<Status>>(&body).unwrap())
  }

}
<commit_msg>default status<commit_after>//! Statuses interface

use self::super::Github;
use rep::{Status, StatusReq};
use rustc_serialize::json;
use std::io::Result;

#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum State {
  pending, success, error, failure
}

impl Default for State {
  fn default() -> State {
    State::pending
  }
}

/// interface for statuses assocaited with a repository
pub struct Statuses<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str
}

impl<'a> Statuses<'a> {
  pub fn new(github: &'a Github<'a>, owner: &'static str, repo: &'static str) -> Statuses<'a> {
    Statuses {
      github: github,
      owner: owner,
      repo: repo
    }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/statuses{}", self.owner, self.repo, more)
  }

  /// creates a new status for a target sha
  pub fn create(&self, sha: &'static str, status: &StatusReq) -> Result<Status> {
    let data = json::encode(&status).unwrap();
    let body = try!(
      self.github.post(
        &self.path(&format!("/{}", sha)),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Status>(&body).unwrap())
  }

  /// lists all statuses associated with a given git sha
  pub fn list(&self, sha: &'static str) -> Result<Vec<Status>> {
    let body = try!(
      self.github.get(
        &format!(
          "/repos/{}/{}/commits/{}/statuses", self.owner, self.repo, sha
        )
      )
    );
    Ok(json::decode::<Vec<Status>>(&body).unwrap())
  }

  /// list the combined statuses for a given git sha
  pub fn combined(&self, sha: &'static str) -> Result<String> {
    let body = try!(
      self.github.get(
        &format!(
          "/repos/{}/{}/commits/{}/status", self.owner, self.repo, sha
        )
      )
    );
    Ok(body)
//    Ok(json::decode::<Vec<Status>>(&body).unwrap())
  }

}
<|endoftext|>


<commit_before>use std::f64::consts::{PI, FRAC_1_PI};
use cgmath::Vector3;
use ideal::{Id, IdVec};
use event::SiteEvent;
use diagram::{Vertex, Cell};

const HEIGHT: usize = 5;

#[derive(Debug)]
pub struct ArcData {
    cell: Cell,
    start: Id<Vertex>,
    center: Option<Vector3<f64>>,
    scan: f64,
    end: f64,
    prev: Arc,
    next: Arc,
    prev_skips: [Arc; HEIGHT],
    next_skips: [Arc; HEIGHT],
}

pub type Arc = Id<ArcData>;

#[derive(Debug)]
pub struct BeachLine {
    pub arcs: IdVec<ArcData>,
    head: Arc,
    len: usize,
    levels: [usize; HEIGHT],
}

impl BeachLine {
    pub fn insert(&mut self, cell: Cell, sites: &[SiteEvent]) -> Arc {
        if self.len > 1 {
            let mut current = self.head;
            let mut level = HEIGHT - 1;
            let mut skips = [Arc::invalid(); HEIGHT];
            let site = &sites[cell.index()];
            loop {
                let next_skip = self.next_skip(current, level);
                let start = self.intersect_with_next(current, site, sites);
                let end = self.intersect_with_next(next_skip, site, sites);
                if start < end {
                    current = next_skip;
                } else {
                    skips[level] = current;
                    if level > 0 {
                        level -= 1;
                    } else {
                        break;
                    }
                }
            }
            let mut next = self.next(current);
            let mut start = self.intersect_with_next(current, site, sites);
            let mut end = self.intersect_with_next(next, site, sites);
            while start < end {
                next = self.next(next);
                start = end;
                end = self.intersect_with_next(next, site, sites);
            }
            current = next;
            let current_cell = self.cell(current);
            let twin = self.create_arc(current_cell);
            let prev = self.prev(current);
            self.insert_after(prev, twin);
            let new = self.create_arc(cell);
            self.insert_after(twin, new);
            self.add_skips(new, &mut skips);
            self.add_skips(twin, &mut skips);
            new
        } else if self.len > 0 {
            let new = self.create_arc(cell);
            let head = self.head;
            self.insert_after(head, new);
            let height = self.insertion_height();
            self.levels[height - 1] += 1;
            for level in 0..height {
                self.set_prev_skip(new, level, head);
                self.set_next_skip(new, level, head);
                self.set_prev_skip(head, level, new);
                self.set_next_skip(head, level, new);
            }
            new
        } else {
            let new = self.create_arc(cell);
            {
                let data = &mut self.arcs[new];
                data.prev = new;
                data.next = new;
                data.prev_skips = [new; HEIGHT];
                data.next_skips = [new; HEIGHT];
            }
            self.head = new;
            self.levels[HEIGHT - 1] += 1;
            self.len += 1;
            new
        }
    }

    fn create_arc(&mut self, cell: Cell) -> Arc {
        self.arcs.push(ArcData {
            cell: cell,
            start: Id::invalid(),
            center: None,
            scan: -1.0,
            end: 0.0,
            prev: Arc::invalid(),
            next: Arc::invalid(),
            prev_skips: [Arc::invalid(); HEIGHT],
            next_skips: [Arc::invalid(); HEIGHT],
        })
    }

    // fn range_end(&mut self, arc1: Arc, arc2: Arc, site: &SiteEvent, diagram: &Diagram) -> f64 {
    //     if self.arcs[arc1].scan < site.theta.value {
    //         self.arcs[arc1].end = self.intersect_with_next(arc1, site, diagram);
    //         self.arcs[arc2].end = self.intersect_with_next(arc2, site, diagram);
    //         self.arcs[arc1].scan = site.theta.value;
    //         self.arcs[arc2].scan = site.theta.value;
    //     }
    //     self.arcs[arc1].end
    // }

    fn skips(&self, arc: Arc, level: usize) -> (Arc, Arc) {
        let data = &self.arcs[arc];
        (data.prev_skips[level], data.next_skips[level])
    }

    // fn prev_skip(&self, arc: Arc, level: usize) -> Arc {
    //     self.arcs[arc].prev_skips[level]
    // }

    fn set_prev_skip(&mut self, arc: Arc, level: usize, prev: Arc) {
        self.arcs[arc].prev_skips[level] = prev;
    }

    fn next_skip(&self, arc: Arc, level: usize) -> Arc {
        self.arcs[arc].next_skips[level]
    }

    fn set_next_skip(&mut self, arc: Arc, level: usize, next: Arc) {
        self.arcs[arc].next_skips[level] = next;
    }

    fn add_skips(&mut self, arc: Arc, skips: &mut[Arc; HEIGHT]) {
        let height = self.insertion_height();
        self.levels[height - 1] += 1;
        for level in 0..height {
            let prev = skips[level];
            let next = self.next_skip(prev, level);
            self.set_prev_skip(arc, level, prev);
            self.set_next_skip(arc, level, next);
            self.set_prev_skip(next, level, arc);
            self.set_next_skip(prev, level, arc);
            skips[level] = arc;
        }
    }

    fn intersect_with_next(&mut self, arc: Arc, site: &SiteEvent, sites: &[SiteEvent]) -> f64 {
        let arc_point = &sites[self.cell(arc).index()];
        let next_point = &sites[self.cell(self.next(arc)).index()];
        let data = &mut self.arcs[arc];
        if data.scan < site.theta.value {
            data.scan = site.theta.value;
            data.end = BeachLine::intersect(arc_point, next_point, site);
        }
        data.end
    }

    fn intersect(site0: &SiteEvent, site1: &SiteEvent, site2: &SiteEvent) -> f64 {
        let u1 = (site2.theta.cos - site1.theta.cos) * site0.theta.sin;
        let u2 = (site2.theta.cos - site0.theta.cos) * site1.theta.sin;
        let a = u1 * site0.phi.cos - u2 * site1.phi.cos;
        let b = u1 * site0.phi.sin - u2 * site1.phi.sin;
        let c = (site0.theta.cos - site1.theta.cos) * site2.theta.sin;
        let length = (a * a + b * b).sqrt();
        let gamma = a.atan2(b);
        let phi_plus_gamma = (c / length).asin();
        BeachLine::wrap(phi_plus_gamma - gamma - site2.phi.value)
    }

    fn wrap(mut phi: f64) -> f64 {
        phi *= 0.5 * FRAC_1_PI;
        phi -= phi.floor();
        phi * 2.0 * PI
    }

    pub fn insert_after(&mut self, prev: Arc, arc: Arc) {
        let next = self.next(prev);
        self.arcs[arc].prev = prev;
        self.arcs[arc].next = next;
        self.arcs[prev].next = arc;
        self.arcs[next].prev = arc;
        self.len += 1;
    }

    pub fn neighbors(&self, arc: Arc) -> (Arc, Arc) {
        let data = &self.arcs[arc];
        (data.prev, data.next)
    }

    pub fn remove(&mut self, arc: Arc) {
        let head = self.head;
        if arc == head {
            let next_skip = self.next_skip(self.head, HEIGHT - 1);
            if next_skip != self.head {
                self.head = next_skip;
            } else {
                let next = self.next(self.head);
                let height = self.height(next);
                self.levels[height - 1] -= 1;
                self.levels[HEIGHT - 1] += 1;
                for level in height..HEIGHT {
                    let next_skip = self.next_skip(self.head, level);
                    self.set_prev_skip(next_skip, level, next);
                    self.set_next_skip(next, level, next_skip);
                    self.set_prev_skip(next, level, head);
                    self.set_next_skip(head, level, next);
                }
                self.head = next;
            }
        }
        self.remove_skips(arc);
        let (prev, next) = self.neighbors(arc);
        self.arcs[prev].next = next;
        self.arcs[next].prev = prev;
        self.len -= 1;
    }

    fn remove_skips(&mut self, arc: Arc) {
        let height = self.height(arc);
        for level in 0..height {
            let (prev_skip, next_skip) = self.skips(arc, level);
            self.set_prev_skip(next_skip, level, prev_skip);
            self.set_next_skip(prev_skip, level, next_skip);
        }
        self.levels[height - 1] -= 1;
    }

    fn height(&self, arc: Arc) -> usize {
        for level in 0..HEIGHT {
            if self.next_skip(arc, level).is_invalid() {
                return level;
            }
        }
        HEIGHT
    }

    pub fn cell(&self, arc: Arc) -> Cell {
        self.arcs[arc].cell
    }

    pub fn start(&self, arc: Arc) -> Id<Vertex> {
        self.arcs[arc].start
    }

    pub fn set_start(&mut self, arc: Arc, start: Id<Vertex>) {
        self.arcs[arc].start = start;
    }

    pub fn center(&self, arc: Arc) -> Option<Vector3<f64>> {
        self.arcs[arc].center
    }

    pub fn attach_circle(&mut self, arc: Arc, center: Vector3<f64>) {
        self.arcs[arc].center = Some(center);
    }

    pub fn detach_circle(&mut self, arc: Arc) {
        self.arcs[arc].center = None;
    }

    pub fn prev(&self, arc: Arc) -> Arc {
        self.arcs[arc].prev
    }

    pub fn next(&self, arc: Arc) -> Arc {
        self.arcs[arc].next
    }

    pub fn clear(&mut self) {
        self.arcs.clear();
        self.head = Arc::invalid();
        self.len = 0;
        self.levels = [0; HEIGHT];
    }

    fn insertion_height(&self) -> usize {
        let mut best_height = 1;
        let mut best_ratio = self.levels[0];
        let mut multiplier = 1;
        for level in 0..HEIGHT {
            let ratio = self.levels[level] * multiplier;
            if ratio < best_ratio {
                best_ratio = ratio;
                best_height = level + 1;
            }
            multiplier *= 2;
        }
        best_height
    }
}

impl Default for BeachLine {
    fn default() -> Self {
        BeachLine {
            arcs: Default::default(),
            head: Arc::invalid(),
            len: 0,
            levels: [0; HEIGHT],
        }
    }
}
<commit_msg>Simplify and rearrange BeachLine<commit_after>use std::f64::consts::{PI, FRAC_1_PI};
use cgmath::Vector3;
use ideal::{Id, IdVec};
use event::SiteEvent;
use diagram::{Vertex, Cell};

const HEIGHT: usize = 5;

#[derive(Debug)]
pub struct ArcData {
    cell: Cell,
    start: Id<Vertex>,
    center: Option<Vector3<f64>>,
    scan: f64,
    end: f64,
    prev: Arc,
    next: Arc,
    prev_skips: [Arc; HEIGHT],
    next_skips: [Arc; HEIGHT],
}

pub type Arc = Id<ArcData>;

#[derive(Debug)]
pub struct BeachLine {
    pub arcs: IdVec<ArcData>,
    head: Arc,
    len: usize,
    levels: [usize; HEIGHT],
}

impl BeachLine {
    pub fn insert(&mut self, cell: Cell, sites: &[SiteEvent]) -> Arc {
        let new = self.create_arc(cell);
        if self.len > 1 {
            let mut current = self.head;
            let mut level = HEIGHT - 1;
            let mut skips = [Arc::invalid(); HEIGHT];
            let site = &sites[cell.index()];
            loop {
                let next_skip = self.next_skip(current, level);
                let start = self.intersect_with_next(current, site, sites);
                let end = self.intersect_with_next(next_skip, site, sites);
                if start < end {
                    current = next_skip;
                } else {
                    skips[level] = current;
                    if level > 0 {
                        level -= 1;
                    } else {
                        break;
                    }
                }
            }
            let mut next = self.next(current);
            let mut start = self.intersect_with_next(current, site, sites);
            let mut end = self.intersect_with_next(next, site, sites);
            while start < end {
                next = self.next(next);
                start = end;
                end = self.intersect_with_next(next, site, sites);
            }
            current = next;
            let current_cell = self.cell(current);
            let twin = self.create_arc(current_cell);
            let prev = self.prev(current);
            self.insert_between(twin, prev, current);
            self.insert_between(new, twin, current);
            self.add_skips(new, &mut skips);
            self.add_skips(twin, &mut skips);
        } else if self.len > 0 {
            let head = self.head;
            self.insert_between(new, head, head);
            let height = self.insertion_height();
            self.levels[height - 1] += 1;
            for level in 0..height {
                self.set_prev_skip(new, level, head);
                self.set_next_skip(new, level, head);
                self.set_prev_skip(head, level, new);
                self.set_next_skip(head, level, new);
            }
        } else {
            self.insert_between(new, new, new);
            {
                let data = &mut self.arcs[new];
                data.prev_skips = [new; HEIGHT];
                data.next_skips = [new; HEIGHT];
            }
            self.head = new;
            self.levels[HEIGHT - 1] += 1;
        }
        new
    }

    pub fn neighbors(&self, arc: Arc) -> (Arc, Arc) {
        let data = &self.arcs[arc];
        (data.prev, data.next)
    }

    pub fn remove(&mut self, arc: Arc) {
        let head = self.head;
        if arc == head {
            let next_skip = self.next_skip(self.head, HEIGHT - 1);
            if next_skip != self.head {
                self.head = next_skip;
            } else {
                let next = self.next(self.head);
                let height = self.height(next);
                self.levels[height - 1] -= 1;
                self.levels[HEIGHT - 1] += 1;
                for level in height..HEIGHT {
                    let next_skip = self.next_skip(self.head, level);
                    self.set_prev_skip(next_skip, level, next);
                    self.set_next_skip(next, level, next_skip);
                    self.set_prev_skip(next, level, head);
                    self.set_next_skip(head, level, next);
                }
                self.head = next;
            }
        }
        self.remove_skips(arc);
        let (prev, next) = self.neighbors(arc);
        self.arcs[prev].next = next;
        self.arcs[next].prev = prev;
        self.len -= 1;
    }

    pub fn cell(&self, arc: Arc) -> Cell {
        self.arcs[arc].cell
    }

    pub fn start(&self, arc: Arc) -> Id<Vertex> {
        self.arcs[arc].start
    }

    pub fn set_start(&mut self, arc: Arc, start: Id<Vertex>) {
        self.arcs[arc].start = start;
    }

    pub fn center(&self, arc: Arc) -> Option<Vector3<f64>> {
        self.arcs[arc].center
    }

    pub fn attach_circle(&mut self, arc: Arc, center: Vector3<f64>) {
        self.arcs[arc].center = Some(center);
    }

    pub fn detach_circle(&mut self, arc: Arc) {
        self.arcs[arc].center = None;
    }

    pub fn prev(&self, arc: Arc) -> Arc {
        self.arcs[arc].prev
    }

    pub fn next(&self, arc: Arc) -> Arc {
        self.arcs[arc].next
    }

    pub fn clear(&mut self) {
        self.arcs.clear();
        self.head = Arc::invalid();
        self.len = 0;
        self.levels = [0; HEIGHT];
    }

    fn create_arc(&mut self, cell: Cell) -> Arc {
        self.arcs.push(ArcData {
            cell: cell,
            start: Id::invalid(),
            center: None,
            scan: -1.0,
            end: 0.0,
            prev: Arc::invalid(),
            next: Arc::invalid(),
            prev_skips: [Arc::invalid(); HEIGHT],
            next_skips: [Arc::invalid(); HEIGHT],
        })
    }

    fn skips(&self, arc: Arc, level: usize) -> (Arc, Arc) {
        let data = &self.arcs[arc];
        (data.prev_skips[level], data.next_skips[level])
    }

    fn set_prev_skip(&mut self, arc: Arc, level: usize, prev: Arc) {
        self.arcs[arc].prev_skips[level] = prev;
    }

    fn next_skip(&self, arc: Arc, level: usize) -> Arc {
        self.arcs[arc].next_skips[level]
    }

    fn set_next_skip(&mut self, arc: Arc, level: usize, next: Arc) {
        self.arcs[arc].next_skips[level] = next;
    }

    fn add_skips(&mut self, arc: Arc, skips: &mut[Arc; HEIGHT]) {
        let height = self.insertion_height();
        self.levels[height - 1] += 1;
        for level in 0..height {
            let prev = skips[level];
            let next = self.next_skip(prev, level);
            self.set_prev_skip(arc, level, prev);
            self.set_next_skip(arc, level, next);
            self.set_prev_skip(next, level, arc);
            self.set_next_skip(prev, level, arc);
            skips[level] = arc;
        }
    }

    fn intersect_with_next(&mut self, arc: Arc, site: &SiteEvent, sites: &[SiteEvent]) -> f64 {
        let arc_point = &sites[self.cell(arc).index()];
        let next_point = &sites[self.cell(self.next(arc)).index()];
        let data = &mut self.arcs[arc];
        if data.scan < site.theta.value {
            data.scan = site.theta.value;
            data.end = BeachLine::intersect(arc_point, next_point, site);
        }
        data.end
    }

    fn intersect(site0: &SiteEvent, site1: &SiteEvent, site2: &SiteEvent) -> f64 {
        let u1 = (site2.theta.cos - site1.theta.cos) * site0.theta.sin;
        let u2 = (site2.theta.cos - site0.theta.cos) * site1.theta.sin;
        let a = u1 * site0.phi.cos - u2 * site1.phi.cos;
        let b = u1 * site0.phi.sin - u2 * site1.phi.sin;
        let c = (site0.theta.cos - site1.theta.cos) * site2.theta.sin;
        let length = (a * a + b * b).sqrt();
        let gamma = a.atan2(b);
        let phi_plus_gamma = (c / length).asin();
        BeachLine::wrap(phi_plus_gamma - gamma - site2.phi.value)
    }

    fn wrap(mut phi: f64) -> f64 {
        phi *= 0.5 * FRAC_1_PI;
        phi -= phi.floor();
        phi * 2.0 * PI
    }

    fn insert_between(&mut self, arc: Arc, prev: Arc, next: Arc) {
        self.arcs[arc].prev = prev;
        self.arcs[arc].next = next;
        self.arcs[prev].next = arc;
        self.arcs[next].prev = arc;
        self.len += 1;
    }

    fn remove_skips(&mut self, arc: Arc) {
        let height = self.height(arc);
        for level in 0..height {
            let (prev_skip, next_skip) = self.skips(arc, level);
            self.set_prev_skip(next_skip, level, prev_skip);
            self.set_next_skip(prev_skip, level, next_skip);
        }
        self.levels[height - 1] -= 1;
    }

    fn height(&self, arc: Arc) -> usize {
        for level in 0..HEIGHT {
            if self.next_skip(arc, level).is_invalid() {
                return level;
            }
        }
        HEIGHT
    }

    fn insertion_height(&self) -> usize {
        let mut best_height = 1;
        let mut best_ratio = self.levels[0];
        let mut multiplier = 1;
        for level in 0..HEIGHT {
            let ratio = self.levels[level] * multiplier;
            if ratio < best_ratio {
                best_ratio = ratio;
                best_height = level + 1;
            }
            multiplier *= 2;
        }
        best_height
    }
}

impl Default for BeachLine {
    fn default() -> Self {
        BeachLine {
            arcs: Default::default(),
            head: Arc::invalid(),
            len: 0,
            levels: [0; HEIGHT],
        }
    }
}
<|endoftext|>


<commit_before>extern crate redis = "redis#0.1";
extern crate extra;
extern crate native;

use redis::Client;
use native::task;

fn bench_set(tid: uint, n: uint) {
  let mut redis = Client::new("127.0.0.1:6379");

  for _ in range(0, n) {
    redis.set("key", "12");
  }

  println!("Thread {} finished", tid);
}

fn main() {
  let before = extra::time::precise_time_ns();

  let concurrency: uint = from_str(std::os::args()[1]).unwrap();
  let repeats: uint = from_str(std::os::args()[2]).unwrap();
  let per_thread: uint = repeats / concurrency;
  let total_reqs = per_thread * concurrency;

  let mut threads = ~[];

  for tid in range(0, concurrency) {
    println!("Thread {} started", tid);

    let (port, chan) = Chan::new();
    task::spawn(proc() {
      bench_set(tid, per_thread);
      chan.send(());
    });
    threads.push(port);
  }

  println!("Waiting for all clients to terminate");
  for port in threads.iter() {
      port.recv();
  }

  let after = extra::time::precise_time_ns();

  let time = ((after - before) / 1_000_000) as f64 / 1000f64;

  println!("Concurrency: {}", concurrency);
  println!("Total requests: {}", total_reqs);
  println!("Total time: {}", time);
  let reqs_per_s = total_reqs as f64 / time;
  println!("Requests per second: {}", reqs_per_s);
}
<commit_msg>time moved out of extra<commit_after>extern crate redis = "redis#0.1";
extern crate time;
extern crate native;

use redis::Client;
use native::task;

fn bench_set(tid: uint, n: uint) {
  let mut redis = Client::new("127.0.0.1:6379");

  for _ in range(0, n) {
    redis.set("key", "12");
  }

  println!("Thread {} finished", tid);
}

fn main() {
  let before = time::precise_time_ns();

  let concurrency: uint = from_str(std::os::args()[1]).unwrap();
  let repeats: uint = from_str(std::os::args()[2]).unwrap();
  let per_thread: uint = repeats / concurrency;
  let total_reqs = per_thread * concurrency;

  let mut threads = ~[];

  for tid in range(0, concurrency) {
    println!("Thread {} started", tid);

    let (port, chan) = Chan::new();
    task::spawn(proc() {
      bench_set(tid, per_thread);
      chan.send(());
    });
    threads.push(port);
  }

  println!("Waiting for all clients to terminate");
  for port in threads.iter() {
      port.recv();
  }

  let after = time::precise_time_ns();

  let time = ((after - before) / 1_000_000) as f64 / 1000f64;

  println!("Concurrency: {}", concurrency);
  println!("Total requests: {}", total_reqs);
  println!("Total time: {}", time);
  let reqs_per_s = total_reqs as f64 / time;
  println!("Requests per second: {}", reqs_per_s);
}
<|endoftext|>


<commit_before>extern crate bincode;
extern crate rustc_serialize;
extern crate rpsrtsrs;
use std::net::{TcpListener, TcpStream};
use std::io::Write;
use std::ops::Deref;
use std::sync::{Mutex,Arc};
use std::thread;

use rpsrtsrs::state::{World, Player, Unit};
use rpsrtsrs::network::{Message};

use bincode::SizeLimit;
use bincode::rustc_serialize::{decode_from, encode};
use bincode::rustc_serialize::DecodingResult;

type SafeWorldState = Arc<Mutex<World>>;

fn handle_client(mut stream: TcpStream, world: SafeWorldState) {

    // handle client hello
    let client_message: DecodingResult<Message> = decode_from(&mut stream, SizeLimit::Bounded(128));
    match client_message {
        Ok(message) => {
            match message {
                Message::ClientHello => {
                    let mut world_lock = world.lock().unwrap();
                    let id = world_lock.game.players.last().map_or(0, |player| player.id+1);
                    // create new player for the newly connected client
                    let mut player = Player::new(id);
                    player.units.push(Unit::new([ 50, 50]));
                    player.units.push(Unit::new([ 50,100]));
                    player.units.push(Unit::new([100, 50]));
                    player.units.push(Unit::new([100,100]));
                    world_lock.game.players.push(player);

                    let encoded: Vec<u8> = encode(&Message::ServerHello(
                            id, world_lock.clone()), SizeLimit::Infinite).unwrap();
                    stream.write(&encoded).unwrap();
                },
                _ => {
                    println!("Did not receive ClientHello{:?}", message);
                    let encoded: Vec<u8> = encode(&Message::Error, SizeLimit::Infinite).unwrap();
                    stream.write(&encoded).unwrap();
                    return
                }
            }
        }
        Err(e) => {
            println!("{:?}", e);
            return
        }
    }

    // GameState loop
    loop {
        let world_lock = world.lock().unwrap();
        let encoded: Vec<u8> = encode(&world_lock.game, SizeLimit::Infinite).unwrap();
        match stream.write(&encoded) {
            Err(e) => {
                println!("Error: {:?}", e);
                return;
            }
            _ =>  thread::sleep_ms(1000),
        };
    }
}

fn update_world(world: SafeWorldState) {
    loop {
        {
            let mut world_lock = world.lock().unwrap();
            for player in world_lock.game.players.iter_mut() {
                for unit in player.units.iter_mut() {
                    unit.update(500);
                    println!("{:?}", unit);
                }
            }
        }
        thread::sleep_ms(500);
    }
}

fn main() {
    let world = Arc::new(Mutex::new(World::new(800, 600)));

    let socket_addr = "127.0.0.1:8080".to_string();
    let tcp_listener = TcpListener::bind(socket_addr.deref()).unwrap();
    println!("Start server: {:?}", tcp_listener);

    let world_clone = world.clone();
    thread::spawn(move || {
        update_world(world_clone);
    });

    for stream in tcp_listener.incoming() {
        match stream {
            Ok(stream) => {
                let world_clone = world.clone();
                println!("Spawning thread...");
                thread::spawn(move || {
                    handle_client(stream, world_clone);
                });
            }
            Err(e) => {
                println!("{:?}", e);
            }
        }
    }
    drop(tcp_listener);
}
<commit_msg>server: Lock world only while encoding<commit_after>extern crate bincode;
extern crate rustc_serialize;
extern crate rpsrtsrs;
use std::net::{TcpListener, TcpStream};
use std::io::Write;
use std::ops::Deref;
use std::sync::{Mutex,Arc};
use std::thread;

use rpsrtsrs::state::{World, Player, Unit};
use rpsrtsrs::network::{Message};

use bincode::SizeLimit;
use bincode::rustc_serialize::{decode_from, encode};
use bincode::rustc_serialize::DecodingResult;

type SafeWorldState = Arc<Mutex<World>>;

fn handle_client(mut stream: TcpStream, world: SafeWorldState) {

    // handle client hello
    let client_message: DecodingResult<Message> = decode_from(&mut stream, SizeLimit::Bounded(128));
    match client_message {
        Ok(message) => {
            match message {
                Message::ClientHello => {
                    let mut world_lock = world.lock().unwrap();
                    let id = world_lock.game.players.last().map_or(0, |player| player.id+1);
                    // create new player for the newly connected client
                    let mut player = Player::new(id);
                    player.units.push(Unit::new([ 50, 50]));
                    player.units.push(Unit::new([ 50,100]));
                    player.units.push(Unit::new([100, 50]));
                    player.units.push(Unit::new([100,100]));
                    world_lock.game.players.push(player);

                    let encoded: Vec<u8> = encode(&Message::ServerHello(
                            id, world_lock.clone()), SizeLimit::Infinite).unwrap();
                    stream.write(&encoded).unwrap();
                },
                _ => {
                    println!("Did not receive ClientHello{:?}", message);
                    let encoded: Vec<u8> = encode(&Message::Error, SizeLimit::Infinite).unwrap();
                    stream.write(&encoded).unwrap();
                    return
                }
            }
        }
        Err(e) => {
            println!("{:?}", e);
            return
        }
    }

    // GameState loop
    loop {
        let encoded: Vec<u8> = {
            let world_lock = world.lock().unwrap();
            encode(&world_lock.game, SizeLimit::Infinite).unwrap()
        };
        match stream.write(&encoded) {
            Err(e) => {
                println!("Error: {:?}", e);
                return;
            }
            _ =>  thread::sleep_ms(1000),
        };
    }
}

fn update_world(world: SafeWorldState) {
    loop {
        {
            let mut world_lock = world.lock().unwrap();
            for player in world_lock.game.players.iter_mut() {
                for unit in player.units.iter_mut() {
                    unit.update(500);
                    println!("{:?}", unit);
                }
            }
        }
        thread::sleep_ms(500);
    }
}

fn main() {
    let world = Arc::new(Mutex::new(World::new(800, 600)));

    let socket_addr = "127.0.0.1:8080".to_string();
    let tcp_listener = TcpListener::bind(socket_addr.deref()).unwrap();
    println!("Start server: {:?}", tcp_listener);

    let world_clone = world.clone();
    thread::spawn(move || {
        update_world(world_clone);
    });

    for stream in tcp_listener.incoming() {
        match stream {
            Ok(stream) => {
                let world_clone = world.clone();
                println!("Spawning thread...");
                thread::spawn(move || {
                    handle_client(stream, world_clone);
                });
            }
            Err(e) => {
                println!("{:?}", e);
            }
        }
    }
    drop(tcp_listener);
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License

use blob::*;
use backend::{MemoryBackend, StoreBackend};
use hash;

use std::sync::Arc;
use quickcheck;

#[test]
fn identity() {
    fn prop(chunks: Vec<Vec<u8>>) -> bool {
        let backend = Arc::new(MemoryBackend::new());

        let blob_index = Arc::new(BlobIndex::new_for_testing().unwrap());
        let bs_p = BlobStore::new(blob_index, backend.clone(), 1024);

        let mut ids = Vec::new();
        for chunk in chunks.iter() {
            ids.push((bs_p.store(chunk.to_owned(),
                                 hash::Hash::new(chunk),
                                 Kind::TreeLeaf,
                                 Box::new(move |_| {})),
                      chunk));
        }

        bs_p.flush();

        // Non-empty chunks must be in the backend now:
        for &(ref id, chunk) in ids.iter() {
            if chunk.len() > 0 {
                match backend.retrieve(&id.persistent_ref.blob_id[..]) {
                    Ok(_) => (),
                    Err(e) => panic!(e),
                }
            }
        }

        // All chunks must be available through the blob store:
        for &(ref id, chunk) in ids.iter() {
            assert_eq!(bs_p.retrieve(&hash::Hash{bytes:id.hash.clone()}, &id.persistent_ref)
                       .unwrap().unwrap(), &chunk[..]);
        }

        return true;
    }
    quickcheck::quickcheck(prop as fn(Vec<Vec<u8>>) -> bool);
}

#[test]
fn identity_with_excessive_flushing() {
    fn prop(chunks: Vec<Vec<u8>>) -> bool {
        let backend = Arc::new(MemoryBackend::new());

        let blob_index = Arc::new(BlobIndex::new_for_testing().unwrap());
        let bs_p = BlobStore::new(blob_index, backend.clone(), 1024);

        let mut ids = Vec::new();
        for chunk in chunks.iter() {
            ids.push((bs_p.store(chunk.to_owned(),
                                 hash::Hash::new(chunk),
                                 Kind::TreeLeaf,
                                 Box::new(move |_| {})),
                      chunk));
            bs_p.flush();
            let &(ref id, chunk) = ids.last().unwrap();
            assert_eq!(bs_p.retrieve(&hash::Hash{bytes:id.hash.clone()}, &id.persistent_ref)
                       .unwrap().unwrap(), &chunk[..]);
        }

        // Non-empty chunks must be in the backend now:
        for &(ref id, chunk) in ids.iter() {
            if chunk.len() > 0 {
                match backend.retrieve(&id.persistent_ref.blob_id[..]) {
                    Ok(_) => (),
                    Err(e) => panic!(e),
                }
            }
        }

        // All chunks must be available through the blob store:
        for &(ref id, chunk) in ids.iter() {
            assert_eq!(bs_p.retrieve(&hash::Hash{bytes:id.hash.clone()}, &id.persistent_ref)
                       .unwrap().unwrap(), &chunk[..]);
        }

        return true;
    }
    quickcheck::quickcheck(prop as fn(Vec<Vec<u8>>) -> bool);
}

#[test]
fn blobid_identity() {
    fn prop(name: Vec<u8>, offset: usize, length: usize) -> bool {
        let blob_id = ChunkRef {
            blob_id: name.to_vec(),
            offset: offset,
            length: length,
            kind: Kind::TreeBranch,
            packing: None,
            key: None,
        };
        let blob_id_bytes = blob_id.as_bytes();
        ChunkRef::from_bytes(&mut &blob_id_bytes[..]).unwrap() == blob_id
    }
    quickcheck::quickcheck(prop as fn(Vec<u8>, usize, usize) -> bool);
}

#[test]
fn blob_reuse() {
    let mut c1 = hash::tree::HashRef{
        hash: vec![],
        persistent_ref: ChunkRef {
        blob_id: Vec::new(),
        offset: 0,
        length: 0,
        kind: Kind::TreeLeaf,
        packing: None,
        key: None,
    }};
    let mut c2 = c1.clone();

    let mut b = Blob::new(1000);
    b.try_append(vec![1, 2, 3], &mut c1).unwrap();
    b.try_append(vec![4, 5, 6], &mut c2).unwrap();

    let mut out = Vec::new();
    b.into_bytes(&mut out);

    assert_eq!(vec![1, 2, 3], Blob::read_chunk(&out, &c1.hash, &c1.persistent_ref).unwrap());
    assert_eq!(vec![4, 5, 6], Blob::read_chunk(&out, &c2.hash, &c2.persistent_ref).unwrap());

    let mut c3 = c2.clone();

    b.try_append(vec![1, 2], &mut c1).unwrap();
    b.try_append(vec![1, 2], &mut c2).unwrap();
    b.try_append(vec![1, 2], &mut c3).unwrap();

    out.clear();
    b.into_bytes(&mut out);
    assert_eq!(vec![1, 2], Blob::read_chunk(&out, &c1.hash, &c1.persistent_ref).unwrap());
    assert_eq!(vec![1, 2], Blob::read_chunk(&out, &c2.hash, &c2.persistent_ref).unwrap());
    assert_eq!(vec![1, 2], Blob::read_chunk(&out, &c3.hash, &c3.persistent_ref).unwrap());
}

#[test]
fn blob_identity() {
    fn prop(chunks: Vec<Vec<u8>>) -> bool {
        let max_size = 10000;
        let mut b = Blob::new(max_size);
        let mut n = 0;
        for chunk in chunks.iter() {
            let mut cref = hash::tree::HashRef{
                hash: vec![],
                persistent_ref: ChunkRef {
                blob_id: Vec::new(),
                offset: 0,
                length: 0,
                kind: Kind::TreeLeaf,
                packing: None,
                key: None,
            }};
            if let Err(_) = b.try_append(chunk.clone(), &mut cref) {
                assert!(b.upperbound_len() + chunk.len() + cref.as_bytes().len() + 50 >= max_size);
                break;
            }
            n = n + 1;
        }

        let mut out = Vec::new();
        b.into_bytes(&mut out);

        if n == 0 {
            assert_eq!(0, out.len());
            return true;
        }

        assert_eq!(max_size, out.len());

        let hrefs = Blob::new(max_size).refs_from_bytes(&out).unwrap();
        assert_eq!(n, hrefs.len());

        // Check recovered ChunkRefs.
        // for (i, cref) in crefs.into_iter().enumerate() {
        // assert!(chunks[i].len() < cref.length);
        // let chunk = Blob::read_chunk(&out, &cref).unwrap();
        // assert_eq!(chunks[i].len(), chunk.len());
        // assert_eq!(&chunks[i], &chunk);
        // }

        true
    }
    quickcheck::quickcheck(prop as fn(Vec<Vec<u8>>) -> bool);
}
<commit_msg>Re-enable final part of blob_identity.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License

use blob::*;
use backend::{MemoryBackend, StoreBackend};
use hash;

use std::sync::Arc;
use quickcheck;

#[test]
fn identity() {
    fn prop(chunks: Vec<Vec<u8>>) -> bool {
        let backend = Arc::new(MemoryBackend::new());

        let blob_index = Arc::new(BlobIndex::new_for_testing().unwrap());
        let bs_p = BlobStore::new(blob_index, backend.clone(), 1024);

        let mut ids = Vec::new();
        for chunk in chunks.iter() {
            ids.push((bs_p.store(chunk.to_owned(),
                                 hash::Hash::new(chunk),
                                 Kind::TreeLeaf,
                                 Box::new(move |_| {})),
                      chunk));
        }

        bs_p.flush();

        // Non-empty chunks must be in the backend now:
        for &(ref id, chunk) in ids.iter() {
            if chunk.len() > 0 {
                match backend.retrieve(&id.persistent_ref.blob_id[..]) {
                    Ok(_) => (),
                    Err(e) => panic!(e),
                }
            }
        }

        // All chunks must be available through the blob store:
        for &(ref id, chunk) in ids.iter() {
            assert_eq!(bs_p.retrieve(&hash::Hash{bytes:id.hash.clone()}, &id.persistent_ref)
                       .unwrap().unwrap(), &chunk[..]);
        }

        return true;
    }
    quickcheck::quickcheck(prop as fn(Vec<Vec<u8>>) -> bool);
}

#[test]
fn identity_with_excessive_flushing() {
    fn prop(chunks: Vec<Vec<u8>>) -> bool {
        let backend = Arc::new(MemoryBackend::new());

        let blob_index = Arc::new(BlobIndex::new_for_testing().unwrap());
        let bs_p = BlobStore::new(blob_index, backend.clone(), 1024);

        let mut ids = Vec::new();
        for chunk in chunks.iter() {
            ids.push((bs_p.store(chunk.to_owned(),
                                 hash::Hash::new(chunk),
                                 Kind::TreeLeaf,
                                 Box::new(move |_| {})),
                      chunk));
            bs_p.flush();
            let &(ref id, chunk) = ids.last().unwrap();
            assert_eq!(bs_p.retrieve(&hash::Hash{bytes:id.hash.clone()}, &id.persistent_ref)
                       .unwrap().unwrap(), &chunk[..]);
        }

        // Non-empty chunks must be in the backend now:
        for &(ref id, chunk) in ids.iter() {
            if chunk.len() > 0 {
                match backend.retrieve(&id.persistent_ref.blob_id[..]) {
                    Ok(_) => (),
                    Err(e) => panic!(e),
                }
            }
        }

        // All chunks must be available through the blob store:
        for &(ref id, chunk) in ids.iter() {
            assert_eq!(bs_p.retrieve(&hash::Hash{bytes:id.hash.clone()}, &id.persistent_ref)
                       .unwrap().unwrap(), &chunk[..]);
        }

        return true;
    }
    quickcheck::quickcheck(prop as fn(Vec<Vec<u8>>) -> bool);
}

#[test]
fn blobid_identity() {
    fn prop(name: Vec<u8>, offset: usize, length: usize) -> bool {
        let blob_id = ChunkRef {
            blob_id: name.to_vec(),
            offset: offset,
            length: length,
            kind: Kind::TreeBranch,
            packing: None,
            key: None,
        };
        let blob_id_bytes = blob_id.as_bytes();
        ChunkRef::from_bytes(&mut &blob_id_bytes[..]).unwrap() == blob_id
    }
    quickcheck::quickcheck(prop as fn(Vec<u8>, usize, usize) -> bool);
}

#[test]
fn blob_reuse() {
    let mut c1 = hash::tree::HashRef {
        hash: vec![],
        persistent_ref: ChunkRef {
            blob_id: Vec::new(),
            offset: 0,
            length: 0,
            kind: Kind::TreeLeaf,
            packing: None,
            key: None,
        },
    };
    let mut c2 = c1.clone();

    let mut b = Blob::new(1000);
    b.try_append(vec![1, 2, 3], &mut c1).unwrap();
    b.try_append(vec![4, 5, 6], &mut c2).unwrap();

    let mut out = Vec::new();
    b.into_bytes(&mut out);

    assert_eq!(vec![1, 2, 3], Blob::read_chunk(&out, &c1.hash, &c1.persistent_ref).unwrap());
    assert_eq!(vec![4, 5, 6], Blob::read_chunk(&out, &c2.hash, &c2.persistent_ref).unwrap());

    let mut c3 = c2.clone();

    b.try_append(vec![1, 2], &mut c1).unwrap();
    b.try_append(vec![1, 2], &mut c2).unwrap();
    b.try_append(vec![1, 2], &mut c3).unwrap();

    out.clear();
    b.into_bytes(&mut out);
    assert_eq!(vec![1, 2], Blob::read_chunk(&out, &c1.hash, &c1.persistent_ref).unwrap());
    assert_eq!(vec![1, 2], Blob::read_chunk(&out, &c2.hash, &c2.persistent_ref).unwrap());
    assert_eq!(vec![1, 2], Blob::read_chunk(&out, &c3.hash, &c3.persistent_ref).unwrap());
}

#[test]
fn blob_identity() {
    fn prop(chunks: Vec<Vec<u8>>) -> bool {
        let max_size = 10000;
        let mut b = Blob::new(max_size);
        let mut n = 0;
        for chunk in chunks.iter() {
            let mut cref = hash::tree::HashRef {
                hash: vec![],
                persistent_ref: ChunkRef {
                    blob_id: Vec::new(),
                    offset: 0,
                    length: 0,
                    kind: Kind::TreeLeaf,
                    packing: None,
                    key: None,
                },
            };
            if let Err(_) = b.try_append(chunk.clone(), &mut cref) {
                assert!(b.upperbound_len() + chunk.len() + cref.as_bytes().len() + 50 >= max_size);
                break;
            }
            n = n + 1;
        }

        let mut out = Vec::new();
        b.into_bytes(&mut out);

        if n == 0 {
            assert_eq!(0, out.len());
            return true;
        }

        assert_eq!(max_size, out.len());

        let hrefs = Blob::new(max_size).refs_from_bytes(&out).unwrap();
        assert_eq!(n, hrefs.len());

        // Check recovered ChunkRefs.
        for (i, href) in hrefs.into_iter().enumerate() {
            assert!(chunks[i].len() < href.persistent_ref.length);
            let chunk = Blob::read_chunk(&out, &href.hash[..], &href.persistent_ref).unwrap();
            assert_eq!(chunks[i].len(), chunk.len());
            assert_eq!(&chunks[i], &chunk);
        }

        true
    }
    quickcheck::quickcheck(prop as fn(Vec<Vec<u8>>) -> bool);
}
<|endoftext|>


<commit_before>//! A simple wait-free, grow-only pagetable, assumes a dense keyspace.
#![allow(unsafe_code)]

use std::{
    alloc::{alloc_zeroed, Layout},
    convert::TryFrom,
    mem::{align_of, size_of},
    sync::atomic::Ordering::{Acquire, Relaxed, Release},
};

use crossbeam_epoch::{pin, Atomic, Guard, Owned, Shared};

use crate::{
    debug_delay,
    pagecache::{Page, PageView},
    Measure, M,
};

#[allow(unused)]
#[doc(hidden)]
pub const PAGETABLE_NODE_SZ: usize = size_of::<Node1>();

const FAN_FACTOR: usize = 18;
const FAN_OUT: usize = 1 << FAN_FACTOR;
const FAN_MASK: usize = FAN_OUT - 1;

pub type PageId = u64;

struct Node1 {
    children: [Atomic<Node2>; FAN_OUT],
}

struct Node2 {
    children: [Atomic<Page>; FAN_OUT],
}

impl Node1 {
    fn new() -> Owned<Self> {
        let size = size_of::<Self>();
        let align = align_of::<Self>();

        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);

            #[allow(clippy::cast_ptr_alignment)]
            let ptr = alloc_zeroed(layout) as *mut Self;

            Owned::from_raw(ptr)
        }
    }
}

impl Node2 {
    fn new() -> Owned<Node2> {
        let size = size_of::<Self>();
        let align = align_of::<Self>();

        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);

            #[allow(clippy::cast_ptr_alignment)]
            let ptr = alloc_zeroed(layout) as *mut Self;

            Owned::from_raw(ptr)
        }
    }
}

impl Drop for Node1 {
    fn drop(&mut self) {
        drop_iter(self.children.iter());
    }
}

impl Drop for Node2 {
    fn drop(&mut self) {
        drop_iter(self.children.iter());
    }
}

fn drop_iter<T>(iter: core::slice::Iter<'_, Atomic<T>>) {
    let guard = pin();
    for child in iter {
        let shared_child = child.load(Relaxed, &guard);
        if shared_child.is_null() {
            // this does not leak because the PageTable is
            // assumed to be dense.
            break;
        }
        unsafe {
            drop(shared_child.into_owned());
        }
    }
}

/// A simple lock-free radix tree.
pub struct PageTable {
    head: Atomic<Node1>,
}

impl Default for PageTable {
    fn default() -> Self {
        let head = Node1::new();
        Self { head: Atomic::from(head) }
    }
}

impl PageTable {
    /// # Panics
    ///
    /// will panic if the item is not null already,
    /// which represents a serious failure to
    /// properly handle lifecycles of pages in the
    /// using system.
    pub fn insert<'g>(
        &self,
        pid: PageId,
        item: Page,
        guard: &'g Guard,
    ) -> PageView<'g> {
        debug_delay();
        let tip = self.traverse(pid, guard);

        let shared = Owned::new(item).into_shared(guard);
        let old = tip.swap(shared, Release, guard);
        assert!(old.is_null());

        PageView { read: shared, entry: tip }
    }

    /// Try to get a value from the tree.
    pub fn get<'g>(
        &self,
        pid: PageId,
        guard: &'g Guard,
    ) -> Option<PageView<'g>> {
        let _measure = Measure::new(&M.get_pagetable);
        debug_delay();
        let tip = self.traverse(pid, guard);

        debug_delay();
        let res = tip.load(Acquire, guard);
        if res.is_null() {
            None
        } else {
            let page_view = PageView { read: res, entry: tip };

            Some(page_view)
        }
    }

    fn traverse<'g>(&self, k: PageId, guard: &'g Guard) -> &'g Atomic<Page> {
        let (l1k, l2k) = split_fanout(k);

        debug_delay();
        let head = self.head.load(Acquire, guard);

        debug_delay();
        let l1 = unsafe { &head.deref().children };

        debug_delay();
        let mut l2_ptr = l1[l1k].load(Acquire, guard);

        if l2_ptr.is_null() {
            let next_child = Node2::new();

            debug_delay();
            let ret = l1[l1k].compare_and_set(
                Shared::null(),
                next_child,
                Release,
                guard,
            );

            l2_ptr = match ret {
                Ok(next_child) => next_child,
                Err(returned) => {
                    drop(returned.new);
                    returned.current
                }
            };
        }

        debug_delay();
        let l2 = unsafe { &l2_ptr.deref().children };

        &l2[l2k]
    }
}

#[inline]
fn split_fanout(id: PageId) -> (usize, usize) {
    // right shift 32 on 32-bit pointer systems panics
    #[cfg(target_pointer_width = "64")]
    assert!(
        id <= 1 << (FAN_FACTOR * 2),
        "trying to access key of {}, which is \
         higher than 2 ^ {}",
        id,
        (FAN_FACTOR * 2)
    );

    let left = id >> FAN_FACTOR;
    let right = id & u64::try_from(FAN_MASK).unwrap();

    (safe_usize(left), safe_usize(right))
}

#[inline]
fn safe_usize(value: PageId) -> usize {
    usize::try_from(value).unwrap()
}

impl Drop for PageTable {
    fn drop(&mut self) {
        let guard = pin();
        let head = self.head.load(Relaxed, &guard);
        unsafe {
            drop(head.into_owned());
        }
    }
}

#[test]
fn test_split_fanout() {
    assert_eq!(
        split_fanout(0b11_1111_1111_1111_1111),
        (0, 0b11_1111_1111_1111_1111)
    );
    assert_eq!(
        split_fanout(0b111_1111_1111_1111_1111),
        (0b1, 0b11_1111_1111_1111_1111)
    );
}
<commit_msg>Allow for storing 45 bits worth of PageId's on 64-bit systems<commit_after>//! A simple wait-free, grow-only pagetable, assumes a dense keyspace.
#![allow(unsafe_code)]

use std::{
    alloc::{alloc_zeroed, Layout},
    convert::TryFrom,
    mem::{align_of, size_of},
    sync::atomic::Ordering::{Acquire, Relaxed, Release},
};

use crossbeam_epoch::{pin, Atomic, Guard, Owned, Shared};

use crate::{
    debug_delay,
    pagecache::{Page, PageView},
    Measure, M,
};

#[allow(unused)]
#[doc(hidden)]
pub const PAGETABLE_NODE_SZ: usize = size_of::<Node1>();

// Allows for around 1 trillion items to be stored
// (assuming 50% node fill, 8 items per leaf)
// and well below 1% of nodes being non-leaf nodes.
// Uses 2gb of virtual memory (almost free until used).
#[cfg(target_pointer_width = "64")]
const DESIRED_BITS: usize = 45;

// Allows for around 2 billion items to be stored
// (assuming 50% node fill, 8 items per leaf)
// and well below 1% of nodes being non-leaf nodes.
// Assumed to be enough for a 32-bit system.
#[cfg(target_pointer_width = "32")]
const DESIRED_BITS: usize = 36;

const NODE2_FAN_FACTOR: usize = 18;
const NODE1_FAN_OUT: usize = 1 << (DESIRED_BITS - NODE2_FAN_FACTOR);
const NODE2_FAN_OUT: usize = 1 << NODE2_FAN_FACTOR;
const FAN_MASK: u64 = (NODE2_FAN_OUT - 1) as u64;

pub type PageId = u64;

struct Node1 {
    children: [Atomic<Node2>; NODE1_FAN_OUT],
}

struct Node2 {
    children: [Atomic<Page>; NODE2_FAN_OUT],
}

impl Node1 {
    fn new() -> Owned<Self> {
        let size = size_of::<Self>();
        let align = align_of::<Self>();

        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);

            #[allow(clippy::cast_ptr_alignment)]
            let ptr = alloc_zeroed(layout) as *mut Self;

            Owned::from_raw(ptr)
        }
    }
}

impl Node2 {
    fn new() -> Owned<Node2> {
        let size = size_of::<Self>();
        let align = align_of::<Self>();

        unsafe {
            let layout = Layout::from_size_align_unchecked(size, align);

            #[allow(clippy::cast_ptr_alignment)]
            let ptr = alloc_zeroed(layout) as *mut Self;

            Owned::from_raw(ptr)
        }
    }
}

impl Drop for Node1 {
    fn drop(&mut self) {
        drop_iter(self.children.iter());
    }
}

impl Drop for Node2 {
    fn drop(&mut self) {
        drop_iter(self.children.iter());
    }
}

fn drop_iter<T>(iter: core::slice::Iter<'_, Atomic<T>>) {
    let guard = pin();
    for child in iter {
        let shared_child = child.load(Relaxed, &guard);
        if shared_child.is_null() {
            // this does not leak because the PageTable is
            // assumed to be dense.
            break;
        }
        unsafe {
            drop(shared_child.into_owned());
        }
    }
}

/// A simple lock-free radix tree.
pub struct PageTable {
    head: Atomic<Node1>,
}

impl Default for PageTable {
    fn default() -> Self {
        let head = Node1::new();
        Self { head: Atomic::from(head) }
    }
}

impl PageTable {
    /// # Panics
    ///
    /// will panic if the item is not null already,
    /// which represents a serious failure to
    /// properly handle lifecycles of pages in the
    /// using system.
    pub fn insert<'g>(
        &self,
        pid: PageId,
        item: Page,
        guard: &'g Guard,
    ) -> PageView<'g> {
        debug_delay();
        let tip = self.traverse(pid, guard);

        let shared = Owned::new(item).into_shared(guard);
        let old = tip.swap(shared, Release, guard);
        assert!(old.is_null());

        PageView { read: shared, entry: tip }
    }

    /// Try to get a value from the tree.
    pub fn get<'g>(
        &self,
        pid: PageId,
        guard: &'g Guard,
    ) -> Option<PageView<'g>> {
        let _measure = Measure::new(&M.get_pagetable);
        debug_delay();
        let tip = self.traverse(pid, guard);

        debug_delay();
        let res = tip.load(Acquire, guard);
        if res.is_null() {
            None
        } else {
            let page_view = PageView { read: res, entry: tip };

            Some(page_view)
        }
    }

    fn traverse<'g>(&self, k: PageId, guard: &'g Guard) -> &'g Atomic<Page> {
        let (l1k, l2k) = split_fanout(k);

        debug_delay();
        let head = self.head.load(Acquire, guard);

        debug_delay();
        let l1 = unsafe { &head.deref().children };

        debug_delay();
        let mut l2_ptr = l1[l1k].load(Acquire, guard);

        if l2_ptr.is_null() {
            let next_child = Node2::new();

            debug_delay();
            let ret = l1[l1k].compare_and_set(
                Shared::null(),
                next_child,
                Release,
                guard,
            );

            l2_ptr = match ret {
                Ok(next_child) => next_child,
                Err(returned) => {
                    drop(returned.new);
                    returned.current
                }
            };
        }

        debug_delay();
        let l2 = unsafe { &l2_ptr.deref().children };

        &l2[l2k]
    }
}

#[inline]
fn split_fanout(id: PageId) -> (usize, usize) {
    // right shift 32 on 32-bit pointer systems panics
    #[cfg(target_pointer_width = "64")]
    assert!(
        id <= 1 << DESIRED_BITS,
        "trying to access key of {}, which is \
         higher than 2 ^ {}",
        id,
        DESIRED_BITS,
    );

    let left = id >> NODE2_FAN_FACTOR;
    let right = id & FAN_MASK;

    (safe_usize(left), safe_usize(right))
}

#[inline]
fn safe_usize(value: PageId) -> usize {
    usize::try_from(value).unwrap()
}

impl Drop for PageTable {
    fn drop(&mut self) {
        let guard = pin();
        let head = self.head.load(Relaxed, &guard);
        unsafe {
            drop(head.into_owned());
        }
    }
}

#[test]
fn test_split_fanout() {
    assert_eq!(
        split_fanout(0b11_1111_1111_1111_1111),
        (0, 0b11_1111_1111_1111_1111)
    );
    assert_eq!(
        split_fanout(0b111_1111_1111_1111_1111),
        (0b1, 0b11_1111_1111_1111_1111)
    );
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::fmt;
use parser;

impl<'chars, T> fmt::Display for parser::UuidParseError<'chars, T>
where
    T: AsRef<[usize]> + fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}: ", self._description());

        match *self {
            parser::UuidParseError::InvalidCharacter {
                expected,
                found,
                index,
            } => write!(
                f,
                "expected {:?}, found {} at {}",
                expected.chars(),
                found,
                index
            ),
            parser::UuidParseError::InvalidGroupCount {
                ref expected,
                found,
            } => write!(
                f,
                "expected {:?}, found {}",
                expected, found
            ),
            parser::UuidParseError::InvalidGroupLength {
                ref expected,
                found,
                group,
            } => write!(
                f,
                "expected {:?}, found {} in group {}",
                expected,
                found,
                group,
            ),
            parser::UuidParseError::InvalidLength {
                ref expected,
                found,
            } => write!(
                f,
                "expected {:?}, found {}",
                expected,
                found
            ),
        }
    }
}
<commit_msg>fix the display message to be more accurate<commit_after>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::fmt;
use parser;

impl<T> fmt::Display for parser::Expected<T>
where
    T: AsRef<[usize]> + fmt::Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            parser::Expected::Any(ref crits) => write!(f, "one of {:?}", crits),
            parser::Expected::Exact(crit) => write!(f, "{}", crit),
            parser::Expected::Range {min, max} => write!(f, "{}..{} inclusive", min, max),
        }
    }
}

impl<'chars, T> fmt::Display for parser::UuidParseError<'chars, T>
where
    T: AsRef<[usize]> + fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}: ", self._description())?;

        match *self {
            parser::UuidParseError::InvalidCharacter {
                expected,
                found,
                index,
            } => write!(
                f,
                "expected {:?}, found {} at {}",
                expected.chars(),
                found,
                index
            ),
            parser::UuidParseError::InvalidGroupCount {
                ref expected,
                found,
            } => write!(
                f,
                "expected {}, found {}",
                expected, found
            ),
            parser::UuidParseError::InvalidGroupLength {
                ref expected,
                found,
                group,
            } => write!(
                f,
                "expected {}, found {} in group {}",
                expected,
                found,
                group,
            ),
            parser::UuidParseError::InvalidLength {
                ref expected,
                found,
            } => write!(
                f,
                "expected {}, found {}",
                expected,
                found
            ),
        }
    }
}
<|endoftext|>


<commit_before>extern crate generic_array;
extern crate libc;
extern crate sha2;
extern crate xattr;

use std::ffi::{OsStr, OsString};
use std::io;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::RawFd;
use std::path::{Component, Path, PathBuf};

use self::generic_array::GenericArray;
use self::generic_array::typenum::U64;
use self::sha2::{Sha512, Digest};
use self::xattr::FileExt;

use catfs::error;
use catfs::error::RError;
use catfs::rlibc;
use catfs::rlibc::File;

pub struct Handle {
    src_file: File,
    cache_file: File,
    dirty: bool,
}

// no-op to workaround the fact that we send the entire CatFS at start
// time, but we never send anything. Could have used Unique but that
// bounds us to rust nightly
unsafe impl Send for Handle {}

fn make_rdwr(f: &mut u32) {
    *f = (*f & !rlibc::O_ACCMODE) | rlibc::O_RDWR;
}

fn maybe_unlinkat(dir: RawFd, path: &AsRef<Path>) -> io::Result<()> {
    if let Err(e) = rlibc::unlinkat(dir, path, 0) {
        if !error::is_enoent(&e) {
            return Err(e);
        }
    }
    return Ok(());
}

fn mkdirat_all(dir: RawFd, path: &AsRef<Path>, mode: u32) -> io::Result<()> {
    let mut p = PathBuf::new();

    for c in path.as_ref().components() {
        if let Component::Normal(n) = c {
            p.push(n);

            if let Err(e) = rlibc::mkdirat(dir, &p, mode) {
                if e.raw_os_error().unwrap() != libc::EEXIST {
                    return Err(e);
                }
            }
        }
    }

    return Ok(());
}

impl Handle {
    pub fn create(
        src_dir: RawFd,
        cache_dir: RawFd,
        path: &AsRef<Path>,
        flags: u32,
        mode: u32,
    ) -> error::Result<Handle> {
        // need to read the cache file for writeback
        let mut cache_flags = flags.clone();
        if (cache_flags & rlibc::O_ACCMODE) == rlibc::O_WRONLY {
            make_rdwr(&mut cache_flags);
        }
        //debug!("create {:b} {:b} {:#o}", flags, cache_flags, mode);

        if let Some(parent) = path.as_ref().parent() {
            mkdirat_all(cache_dir, &parent, 0o777)?;
        }

        let src_file = File::openat(src_dir, path, flags, mode)?;
        // we are able to create the src file, then the cache file
        // shouldn't be here, but it could be because of bug/crash,
        // so unlink it first
        maybe_unlinkat(cache_dir, path)?;

        return Ok(Handle {
            src_file: src_file,
            cache_file: File::openat(cache_dir, path, cache_flags, mode)?,
            dirty: true,
        });
    }

    pub fn open(
        src_dir: RawFd,
        cache_dir: RawFd,
        path: &AsRef<Path>,
        flags: u32,
        cache_valid_if_present: bool,
    ) -> error::Result<Handle> {
        // even if file is open for write only, I still need to be
        // able to read the src for read-modify-write
        let mut flags = flags;
        if (flags & rlibc::O_ACCMODE) == rlibc::O_WRONLY {
            make_rdwr(&mut flags);
        }

        let valid = Handle::validate_cache(src_dir, cache_dir, &path, cache_valid_if_present)?;
        debug!(
            "{:?} {} a valid cache file",
            path.as_ref(),
            if valid { "is" } else { "is not" },
        );
        let mut cache_flags = flags.clone();

        if !valid {
            // mkdir the parents
            if let Some(parent) = path.as_ref().parent() {
                mkdirat_all(cache_dir, &parent, 0o777)?;
            }
            // need to cache this file so need to open it for write
            cache_flags |= rlibc::O_CREAT;
            if (cache_flags & rlibc::O_ACCMODE) == rlibc::O_RDONLY {
                make_rdwr(&mut cache_flags);
            }
        }

        let src_file: File;
        if valid && (flags & rlibc::O_ACCMODE) == rlibc::O_RDONLY {
            src_file = Default::default();
        } else {
            src_file = File::openat(src_dir, path, flags, 0o666)?;
        }

        let handle = Handle {
            src_file: src_file,
            cache_file: File::openat(cache_dir, path, cache_flags, 0o666)?,
            dirty: false,
        };

        if !valid && (flags & rlibc::O_TRUNC) == 0 {
            debug!("read ahead {:?}", path.as_ref());
            handle.copy(true)?;
        }

        return Ok(handle);
    }

    // the equivalent of:
    // getfattr -e hex --match=.* -d $f 2>/dev/null | grep =;
    // /usr/bin/stat -t --printf "%s\n%Y\n" $f
    // note that mtime is printed first and then size
    pub fn src_str_to_checksum(f: &File) -> error::Result<OsString> {
        let mut s = OsString::new();
        match f.list_xattr() {
            Ok(attrs) => {
                for x in attrs {
                    if let Some(v) = f.get_xattr(&x)? {
                        s.push(x);
                        s.push(OsStr::new("="));
                        s.push("0x");
                        for b in v {
                            s.push(format!("{:x}", b));
                        }
                        s.push("\n");
                    }
                }
            }
            Err(e) => {
                if e.raw_os_error().unwrap() != libc::ENOTSUP {
                    return Err(RError::from(e));
                }
            }
        }

        let st = f.stat()?;
        s.push(format!("{}\n", st.st_mtime));
        s.push(format!("{}\n", st.st_size));
        return Ok(s);
    }

    fn src_chksum(f: &File) -> error::Result<GenericArray<u8, U64>> {
        let s = Handle::src_str_to_checksum(f)?;
        let mut h = Sha512::default();
        h.input(s.as_bytes());
        return Ok(h.result());
    }

    fn set_pristine(&self, pristine: bool) -> error::Result<()> {
        if pristine {
            self.cache_file.set_xattr(
                "user.catfs.src_chksum",
                Handle::src_chksum(&self.src_file)?
                    .as_slice(),
            )?;
        } else {
            self.cache_file.remove_xattr("user.catfs.src_chksum")?;
        }
        return Ok(());
    }

    fn is_pristine(src_file: &File, cache_file: &File) -> error::Result<bool> {
        if let Some(v) = cache_file.get_xattr("user.catfs.src_chksum")? {
            return Ok(v == Handle::src_chksum(src_file)?.as_slice());
        }

        return Ok(false);
    }

    pub fn unlink(src_dir: RawFd, cache_dir: RawFd, path: &AsRef<Path>) -> io::Result<()> {
        maybe_unlinkat(cache_dir, path)?;
        return rlibc::unlinkat(src_dir, path, 0);
    }

    fn validate_cache(
        src_dir: RawFd,
        cache_dir: RawFd,
        path: &AsRef<Path>,
        cache_valid_if_present: bool,
    ) -> error::Result<bool> {
        match File::openat(src_dir, path, rlibc::O_RDONLY, 0) {
            Ok(mut src_file) => {
                match File::openat(cache_dir, path, rlibc::O_RDONLY, 0) {
                    Ok(mut cache_file) => {
                        let valid: bool;
                        if cache_valid_if_present || Handle::is_pristine(&src_file, &cache_file)? {
                            valid = true;
                        } else {
                            valid = false;
                            rlibc::unlinkat(cache_dir, path, 0)?;
                        }
                        src_file.close()?;
                        cache_file.close()?;
                        return Ok(valid);
                    }
                    Err(e) => {
                        src_file.close()?;
                        if error::try_enoent(e)? {
                            return Ok(false);
                        }
                    }
                }
            }
            Err(e) => {
                if error::try_enoent(e)? {
                    // the source file doesn't exist, the cache file shouldn't either
                    maybe_unlinkat(cache_dir, path)?;
                }
            }
        }

        return Ok(false);
    }

    pub fn read(&self, offset: u64, buf: &mut [u8]) -> error::Result<usize> {
        let nwant = buf.len();
        let mut bytes_read: usize = 0;

        while bytes_read < nwant {
            match self.cache_file.read_at(
                &mut buf[bytes_read..],
                offset + (bytes_read as u64),
            ) {
                Ok(nread) => {
                    if nread == 0 {
                        return Ok(bytes_read);
                    }
                    bytes_read += nread;
                }
                Err(e) => {
                    if bytes_read > 0 {
                        return Ok(bytes_read);
                    } else {
                        return Err(RError::from(e));
                    }
                }
            }
        }

        return Ok(bytes_read);
    }

    pub fn write(&mut self, offset: u64, buf: &[u8]) -> error::Result<usize> {
        let nwant = buf.len();
        let mut bytes_written: usize = 0;

        if !self.dirty {
            // assumes that the metadata will hit the disk before the
            // incoming data will, and not flushing
            self.set_pristine(false)?;
        }

        while bytes_written < nwant {
            match self.cache_file.write_at(
                &buf[bytes_written..],
                offset + (bytes_written as u64),
            ) {
                Ok(nwritten) => {
                    if nwritten == 0 {
                        return Ok(bytes_written);
                    }
                    bytes_written += nwritten;
                }
                Err(e) => {
                    if bytes_written > 0 {
                        return Ok(bytes_written);
                    } else {
                        return Err(RError::from(e));
                    }
                }
            }
        }

        if bytes_written != 0 {
            self.dirty = true;
        }

        return Ok(bytes_written);
    }

    pub fn flush(&mut self) -> error::Result<(bool)> {
        let mut flushed_to_src = false;
        if self.dirty {
            self.copy(false)?;
            self.dirty = false;
            self.cache_file.flush()?;
            // if file was opened for read only and cache is valid we
            // might not have opened src_file
            if self.src_file.valid() {
                self.src_file.flush()?;
                flushed_to_src = true;
            }
        }
        return Ok(flushed_to_src);
    }

    fn copy_user(rh: &File, wh: &File) -> error::Result<()> {
        let mut buf = [0u8; 32 * 1024];
        let mut offset = 0;
        loop {
            let nread = rh.read_at(&mut buf, offset)?;
            if nread == 0 {
                break;
            }
            wh.write_at(&buf[..nread], offset)?;
            offset += nread as u64;
        }
        return Ok(());
    }

    fn copy_splice(rh: &File, wh: &File) -> error::Result<()> {
        let (pin, pout) = rlibc::pipe()?;

        let mut offset = 0;
        loop {
            let nread = rlibc::splice(rh.as_raw_fd(), offset, pout, -1, 128 * 1024)?;
            if nread == 0 {
                break;
            }

            let mut written = 0;
            while written < nread {
                let nxfer = rlibc::splice(pin, -1, wh.as_raw_fd(), offset, 128 * 1024)?;

                written += nxfer;
                offset += nxfer as i64;
            }
        }

        if let Err(e) = rlibc::close(pin) {
            rlibc::close(pout)?;
            return Err(RError::from(e));
        } else {
            rlibc::close(pout)?;
        }

        return Ok(());
    }

    fn copy(&self, to_cache: bool) -> error::Result<()> {
        let rh: &File;
        let wh: &File;
        if to_cache {
            rh = &self.src_file;
            wh = &self.cache_file;
        } else {
            rh = &self.cache_file;
            wh = &self.src_file;
        }

        wh.set_size(rh.filesize()?)?;

        if let Err(e) = Handle::copy_splice(rh, wh) {
            if e.raw_os_error().unwrap() == libc::EINVAL {
                Handle::copy_user(rh, wh)?;
            }
        }

        self.set_pristine(true)?;
        return Ok(());
    }
}

impl Drop for Handle {
    fn drop(&mut self) {
        if let Err(e) = self.cache_file.close() {
            error!("!close(cache) = {}", RError::from(e));
        }
        if self.src_file.valid() {
            if let Err(e) = self.src_file.close() {
                error!("!close(src) = {}", RError::from(e));
            }
        }
    }
}
<commit_msg>correct comment<commit_after>extern crate generic_array;
extern crate libc;
extern crate sha2;
extern crate xattr;

use std::ffi::{OsStr, OsString};
use std::io;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::RawFd;
use std::path::{Component, Path, PathBuf};

use self::generic_array::GenericArray;
use self::generic_array::typenum::U64;
use self::sha2::{Sha512, Digest};
use self::xattr::FileExt;

use catfs::error;
use catfs::error::RError;
use catfs::rlibc;
use catfs::rlibc::File;

pub struct Handle {
    src_file: File,
    cache_file: File,
    dirty: bool,
}

// no-op to workaround the fact that we send the entire CatFS at start
// time, but we never send anything. Could have used Unique but that
// bounds us to rust nightly
unsafe impl Send for Handle {}

fn make_rdwr(f: &mut u32) {
    *f = (*f & !rlibc::O_ACCMODE) | rlibc::O_RDWR;
}

fn maybe_unlinkat(dir: RawFd, path: &AsRef<Path>) -> io::Result<()> {
    if let Err(e) = rlibc::unlinkat(dir, path, 0) {
        if !error::is_enoent(&e) {
            return Err(e);
        }
    }
    return Ok(());
}

fn mkdirat_all(dir: RawFd, path: &AsRef<Path>, mode: u32) -> io::Result<()> {
    let mut p = PathBuf::new();

    for c in path.as_ref().components() {
        if let Component::Normal(n) = c {
            p.push(n);

            if let Err(e) = rlibc::mkdirat(dir, &p, mode) {
                if e.raw_os_error().unwrap() != libc::EEXIST {
                    return Err(e);
                }
            }
        }
    }

    return Ok(());
}

impl Handle {
    pub fn create(
        src_dir: RawFd,
        cache_dir: RawFd,
        path: &AsRef<Path>,
        flags: u32,
        mode: u32,
    ) -> error::Result<Handle> {
        // need to read the cache file for writeback
        let mut cache_flags = flags.clone();
        if (cache_flags & rlibc::O_ACCMODE) == rlibc::O_WRONLY {
            make_rdwr(&mut cache_flags);
        }
        //debug!("create {:b} {:b} {:#o}", flags, cache_flags, mode);

        if let Some(parent) = path.as_ref().parent() {
            mkdirat_all(cache_dir, &parent, 0o777)?;
        }

        let src_file = File::openat(src_dir, path, flags, mode)?;
        // we are able to create the src file, then the cache file
        // shouldn't be here, but it could be because of bug/crash,
        // so unlink it first
        maybe_unlinkat(cache_dir, path)?;

        return Ok(Handle {
            src_file: src_file,
            cache_file: File::openat(cache_dir, path, cache_flags, mode)?,
            dirty: true,
        });
    }

    pub fn open(
        src_dir: RawFd,
        cache_dir: RawFd,
        path: &AsRef<Path>,
        flags: u32,
        cache_valid_if_present: bool,
    ) -> error::Result<Handle> {
        // even if file is open for write only, I still need to be
        // able to read the src for read-modify-write
        let mut flags = flags;
        if (flags & rlibc::O_ACCMODE) == rlibc::O_WRONLY {
            make_rdwr(&mut flags);
        }

        let valid = Handle::validate_cache(src_dir, cache_dir, &path, cache_valid_if_present)?;
        debug!(
            "{:?} {} a valid cache file",
            path.as_ref(),
            if valid { "is" } else { "is not" },
        );
        let mut cache_flags = flags.clone();

        if !valid {
            // mkdir the parents
            if let Some(parent) = path.as_ref().parent() {
                mkdirat_all(cache_dir, &parent, 0o777)?;
            }
            // need to cache this file so need to open it for write
            cache_flags |= rlibc::O_CREAT;
            if (cache_flags & rlibc::O_ACCMODE) == rlibc::O_RDONLY {
                make_rdwr(&mut cache_flags);
            }
        }

        let src_file: File;
        if valid && (flags & rlibc::O_ACCMODE) == rlibc::O_RDONLY {
            src_file = Default::default();
        } else {
            src_file = File::openat(src_dir, path, flags, 0o666)?;
        }

        let handle = Handle {
            src_file: src_file,
            cache_file: File::openat(cache_dir, path, cache_flags, 0o666)?,
            dirty: false,
        };

        if !valid && (flags & rlibc::O_TRUNC) == 0 {
            debug!("read ahead {:?}", path.as_ref());
            handle.copy(true)?;
        }

        return Ok(handle);
    }

    // the equivalent of:
    // getfattr -e hex --match=.* -d $f 2>/dev/null | grep =;
    // /usr/bin/stat -t --printf "%Y\n%s\n" $f
    // note that mtime is printed first and then size
    pub fn src_str_to_checksum(f: &File) -> error::Result<OsString> {
        let mut s = OsString::new();
        match f.list_xattr() {
            Ok(attrs) => {
                for x in attrs {
                    if let Some(v) = f.get_xattr(&x)? {
                        s.push(x);
                        s.push(OsStr::new("="));
                        s.push("0x");
                        for b in v {
                            s.push(format!("{:x}", b));
                        }
                        s.push("\n");
                    }
                }
            }
            Err(e) => {
                if e.raw_os_error().unwrap() != libc::ENOTSUP {
                    return Err(RError::from(e));
                }
            }
        }

        let st = f.stat()?;
        s.push(format!("{}\n", st.st_mtime));
        s.push(format!("{}\n", st.st_size));
        return Ok(s);
    }

    fn src_chksum(f: &File) -> error::Result<GenericArray<u8, U64>> {
        let s = Handle::src_str_to_checksum(f)?;
        let mut h = Sha512::default();
        h.input(s.as_bytes());
        return Ok(h.result());
    }

    fn set_pristine(&self, pristine: bool) -> error::Result<()> {
        if pristine {
            self.cache_file.set_xattr(
                "user.catfs.src_chksum",
                Handle::src_chksum(&self.src_file)?
                    .as_slice(),
            )?;
        } else {
            self.cache_file.remove_xattr("user.catfs.src_chksum")?;
        }
        return Ok(());
    }

    fn is_pristine(src_file: &File, cache_file: &File) -> error::Result<bool> {
        if let Some(v) = cache_file.get_xattr("user.catfs.src_chksum")? {
            return Ok(v == Handle::src_chksum(src_file)?.as_slice());
        }

        return Ok(false);
    }

    pub fn unlink(src_dir: RawFd, cache_dir: RawFd, path: &AsRef<Path>) -> io::Result<()> {
        maybe_unlinkat(cache_dir, path)?;
        return rlibc::unlinkat(src_dir, path, 0);
    }

    fn validate_cache(
        src_dir: RawFd,
        cache_dir: RawFd,
        path: &AsRef<Path>,
        cache_valid_if_present: bool,
    ) -> error::Result<bool> {
        match File::openat(src_dir, path, rlibc::O_RDONLY, 0) {
            Ok(mut src_file) => {
                match File::openat(cache_dir, path, rlibc::O_RDONLY, 0) {
                    Ok(mut cache_file) => {
                        let valid: bool;
                        if cache_valid_if_present || Handle::is_pristine(&src_file, &cache_file)? {
                            valid = true;
                        } else {
                            valid = false;
                            rlibc::unlinkat(cache_dir, path, 0)?;
                        }
                        src_file.close()?;
                        cache_file.close()?;
                        return Ok(valid);
                    }
                    Err(e) => {
                        src_file.close()?;
                        if error::try_enoent(e)? {
                            return Ok(false);
                        }
                    }
                }
            }
            Err(e) => {
                if error::try_enoent(e)? {
                    // the source file doesn't exist, the cache file shouldn't either
                    maybe_unlinkat(cache_dir, path)?;
                }
            }
        }

        return Ok(false);
    }

    pub fn read(&self, offset: u64, buf: &mut [u8]) -> error::Result<usize> {
        let nwant = buf.len();
        let mut bytes_read: usize = 0;

        while bytes_read < nwant {
            match self.cache_file.read_at(
                &mut buf[bytes_read..],
                offset + (bytes_read as u64),
            ) {
                Ok(nread) => {
                    if nread == 0 {
                        return Ok(bytes_read);
                    }
                    bytes_read += nread;
                }
                Err(e) => {
                    if bytes_read > 0 {
                        return Ok(bytes_read);
                    } else {
                        return Err(RError::from(e));
                    }
                }
            }
        }

        return Ok(bytes_read);
    }

    pub fn write(&mut self, offset: u64, buf: &[u8]) -> error::Result<usize> {
        let nwant = buf.len();
        let mut bytes_written: usize = 0;

        if !self.dirty {
            // assumes that the metadata will hit the disk before the
            // incoming data will, and not flushing
            self.set_pristine(false)?;
        }

        while bytes_written < nwant {
            match self.cache_file.write_at(
                &buf[bytes_written..],
                offset + (bytes_written as u64),
            ) {
                Ok(nwritten) => {
                    if nwritten == 0 {
                        return Ok(bytes_written);
                    }
                    bytes_written += nwritten;
                }
                Err(e) => {
                    if bytes_written > 0 {
                        return Ok(bytes_written);
                    } else {
                        return Err(RError::from(e));
                    }
                }
            }
        }

        if bytes_written != 0 {
            self.dirty = true;
        }

        return Ok(bytes_written);
    }

    pub fn flush(&mut self) -> error::Result<(bool)> {
        let mut flushed_to_src = false;
        if self.dirty {
            self.copy(false)?;
            self.dirty = false;
            self.cache_file.flush()?;
            // if file was opened for read only and cache is valid we
            // might not have opened src_file
            if self.src_file.valid() {
                self.src_file.flush()?;
                flushed_to_src = true;
            }
        }
        return Ok(flushed_to_src);
    }

    fn copy_user(rh: &File, wh: &File) -> error::Result<()> {
        let mut buf = [0u8; 32 * 1024];
        let mut offset = 0;
        loop {
            let nread = rh.read_at(&mut buf, offset)?;
            if nread == 0 {
                break;
            }
            wh.write_at(&buf[..nread], offset)?;
            offset += nread as u64;
        }
        return Ok(());
    }

    fn copy_splice(rh: &File, wh: &File) -> error::Result<()> {
        let (pin, pout) = rlibc::pipe()?;

        let mut offset = 0;
        loop {
            let nread = rlibc::splice(rh.as_raw_fd(), offset, pout, -1, 128 * 1024)?;
            if nread == 0 {
                break;
            }

            let mut written = 0;
            while written < nread {
                let nxfer = rlibc::splice(pin, -1, wh.as_raw_fd(), offset, 128 * 1024)?;

                written += nxfer;
                offset += nxfer as i64;
            }
        }

        if let Err(e) = rlibc::close(pin) {
            rlibc::close(pout)?;
            return Err(RError::from(e));
        } else {
            rlibc::close(pout)?;
        }

        return Ok(());
    }

    fn copy(&self, to_cache: bool) -> error::Result<()> {
        let rh: &File;
        let wh: &File;
        if to_cache {
            rh = &self.src_file;
            wh = &self.cache_file;
        } else {
            rh = &self.cache_file;
            wh = &self.src_file;
        }

        wh.set_size(rh.filesize()?)?;

        if let Err(e) = Handle::copy_splice(rh, wh) {
            if e.raw_os_error().unwrap() == libc::EINVAL {
                Handle::copy_user(rh, wh)?;
            }
        }

        self.set_pristine(true)?;
        return Ok(());
    }
}

impl Drop for Handle {
    fn drop(&mut self) {
        if let Err(e) = self.cache_file.close() {
            error!("!close(cache) = {}", RError::from(e));
        }
        if self.src_file.valid() {
            if let Err(e) = self.src_file.close() {
                error!("!close(src) = {}", RError::from(e));
            }
        }
    }
}
<|endoftext|>