<commit_before>// #![cfg_attr(test, feature(test))]
extern crate time;
extern crate num_cpus;
extern crate scoped_threadpool;

use time::precise_time_s;
use scoped_threadpool::Pool;
use std::mem;

///////////////////////////////////////////////////////////////////////////////
// 1. Calibration
///////////////////////////////////////////////////////////////////////////////
const ALPHA: f64 = 0.33333333333;  // Elasticity of output w.r.t. capital
const BETA: f64 = 0.95;           // Discount factor

// Productivity values
const PRODUCTIVITY: [f64; 5] = [0.9792, 0.9896, 1.0000, 1.0106, 1.0212];

// Transition matrix
static TRANSITIONS: [[f64; 5]; 5] = [[0.9727, 0.0273, 0.0000, 0.0000, 0.0000],
                                     [0.0041, 0.9806, 0.0153, 0.0000, 0.0000],
                                     [0.0000, 0.0082, 0.9837, 0.0082, 0.0000],
                                     [0.0000, 0.0000, 0.0153, 0.9806, 0.0041],
                                     [0.0000, 0.0000, 0.0000, 0.0273, 0.9727]];

// Dimensions to generate the grid of capital
const GRID_CAPITAL: usize = 17820;
const GRID_PRODUCTIVITY: usize = 5;

fn solve(print: bool) -> f64 {
  /////////////////////////////////////////////////////////////////////////////
  // 2. Steady State
  /////////////////////////////////////////////////////////////////////////////

    let thread_count = num_cpus::get();
    let mut pool = Pool::new(thread_count as u32);

    let capital_steady_state: f64 = (ALPHA * BETA).powf(1_f64 / (1_f64 - ALPHA));
    let output_steady_state: f64 = capital_steady_state.powf(ALPHA);
    let consumption_steady_state: f64 = output_steady_state - capital_steady_state;

    if print {
        println!("Output = {}, Capital = {}, Consumption = {}",
                 output_steady_state,
                 capital_steady_state,
                 consumption_steady_state);
    }

    let mut grid_capital = [0f64; GRID_CAPITAL];

    for (i, val) in grid_capital.iter_mut().enumerate() {
        *val = 0.5 * capital_steady_state + 0.00001 * (i as f64)
    }

    // 3. Required matrices and vectors
    let mut values: [Vec<f64>; GRID_PRODUCTIVITY] = [
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
    ];

    let mut policies: [Vec<f64>; GRID_PRODUCTIVITY] = [
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
    ];

    let mut expected_values: [Vec<f64>; GRID_PRODUCTIVITY] = [
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
    ];

    // 4. We pre-build output for each point in the grid
    let output : Vec<[f64; GRID_PRODUCTIVITY]> = (0..GRID_CAPITAL).map(|capital_idx| {
        let mut arr = [0.0; GRID_PRODUCTIVITY];

        for (productivity_idx, slot) in arr.iter_mut().enumerate() {
            *slot = PRODUCTIVITY[productivity_idx] * grid_capital[capital_idx].powf(ALPHA)
        }

        arr
    }).collect();

  // 5. Main iteration
  // TODO: one could implement a macro for the multiple declarations
    let mut max_difference = 10_f64;
    const TOLERANCE: f64 = 0.0000001; // compiler warn: variable does not need to be mutable

    let mut iteration = 0;

    // small array to split where the writes are going, so we don't need a mutex
    let mut diffs = [-100000.0; GRID_PRODUCTIVITY];

    while max_difference > TOLERANCE {
        pool.scoped(|scoped| {
            for (expected_values, transitions) in expected_values.iter_mut()
                                                                       .zip(TRANSITIONS.iter()) {
                // Only capture refs
                let values = &values;

                scoped.execute(move || {
                    for (idx, expected_value) in expected_values.iter_mut().enumerate() {
                        *expected_value = transitions.iter()
                                                     .zip(values.iter())
                                                     .fold(0.0f64, |acc, (transition, value_fns)| {
                            acc + (transition * value_fns[idx])
                        });
                    }
                });
            }
        });

        pool.scoped(|scoped| {
            for (productivity_idx, (((policies, value_fns), max_difference), expected_values)) in policies.iter_mut()
                                                                         .zip(values.iter_mut())
                                                                         .zip(diffs.iter_mut())
                                                                         .zip(expected_values.iter())
                                                                         .enumerate() {
                *max_difference = -100000.0;

                // Only capture refs
                let output = &output;

                scoped.execute(move || {
                    // We start from previous choice (monotonicity of policy function)
                    let mut grid_capital_next_period = 0;

                    for ((policy, output), value_fn) in policies.iter_mut()
                                                                .zip(output.iter())
                                                                .zip(value_fns.iter_mut()) {
                        let mut value_high = -100000.0;
                        let mut capital_choice = grid_capital[0];
                        let output_cache = &output[productivity_idx];

                        for capital_next_period in grid_capital_next_period..GRID_CAPITAL {
                            let consumption = output_cache - &grid_capital[capital_next_period];
                            let value_provisional = (1_f64 - BETA) * (consumption.ln()) +
                                                    BETA *
                                                    expected_values[capital_next_period];

                            if value_provisional > value_high {
                                value_high = value_provisional;
                                capital_choice = grid_capital[capital_next_period];
                                grid_capital_next_period = capital_next_period;
                            } else {
                                break; // We break when we have achieved the max
                            }
                        }

                        let old = mem::replace(value_fn, value_high);
                        let diff = (old - value_high).abs();
                        if diff > *max_difference {
                            *max_difference = diff
                        }

                        *policy = capital_choice;
                    }
                })
            }
        });

        max_difference = -100000.0;
        for &diff in &diffs {
            if diff > max_difference {
                max_difference = diff
            }
        }

        iteration += 1;
        if print && (iteration % 10 == 0 || iteration == 1) {
            println!("Iteration = {}, Sup Diff = {}", iteration, max_difference);
        }
    }

    if print {
        println!("Iteration = {}, Sup Diff = {}", iteration, max_difference);
    }

    policies[2][999]
}

fn main() {
    use std::env::args;

    let sample = args().any(|arg| arg == "--sample");

    if sample {
        let mut samples = (0..5).map(|i| {
            let cpu0 = precise_time_s();
            let result = solve(false);
            let cpu1 = precise_time_s();

            assert_eq!(result, 0.1465491436956954);

            let diff = cpu1 - cpu0;
            println!("Sample #{}, Time: {}s", i + 1, diff);
            diff
        }).collect::<Vec<f64>>();

        samples.sort_by(|a, b| a.partial_cmp(b).unwrap());
        println!("\nMedian time is = {}", samples[2]);
    } else {
        let cpu0 = precise_time_s();
        let result = solve(true);
        let cpu1 = precise_time_s();

        println!("My check = {}\n", result);
        assert_eq!(result, 0.1465491436956954);
        println!("Elapsed time is = {}", cpu1 - cpu0);
    }
}

// FIXME: Can't use bench as the loop is too slow (takes 8mins to get samples)
// #[cfg(test)]
// mod test {
//     extern crate test;
//     use self::test::Bencher;
//     use super::solve;

//     #[bench]
//     fn bench(b: &mut Bencher) {
//         b.iter(|| {
//             // use `test::black_box` to prevent compiler optimizations from disregarding
//             // unused values
//             test::black_box(solve(false));
//         });
//     }
// }
<commit_msg>Invert data layout for outputs and some minor cleanup<commit_after>extern crate time;
extern crate num_cpus;
extern crate scoped_threadpool;

use time::precise_time_s;
use scoped_threadpool::Pool;
use std::mem;

// 1. Calibration
const ALPHA: f64 = 0.33333333333;  // Elasticity of output w.r.t. capital
const BETA: f64 = 0.95;           // Discount factor

// Productivity values
const PRODUCTIVITY: [f64; 5] = [0.9792, 0.9896, 1.0000, 1.0106, 1.0212];

// Transition matrix
static TRANSITIONS: [[f64; 5]; 5] = [[0.9727, 0.0273, 0.0000, 0.0000, 0.0000],
                                     [0.0041, 0.9806, 0.0153, 0.0000, 0.0000],
                                     [0.0000, 0.0082, 0.9837, 0.0082, 0.0000],
                                     [0.0000, 0.0000, 0.0153, 0.9806, 0.0041],
                                     [0.0000, 0.0000, 0.0000, 0.0273, 0.9727]];

// Dimensions to generate the grid of capital
const GRID_CAPITAL: usize = 17820;
const GRID_PRODUCTIVITY: usize = 5;

fn solve(pool: &mut Pool, print: bool) -> f64 {
    // 2. Steady State
    let capital_steady_state = (ALPHA * BETA).powf(1_f64 / (1_f64 - ALPHA));
    let output_steady_state = capital_steady_state.powf(ALPHA);
    let consumption_steady_state = output_steady_state - capital_steady_state;

    if print {
        println!("Output = {}, Capital = {}, Consumption = {}",
                 output_steady_state,
                 capital_steady_state,
                 consumption_steady_state);
    }

    let mut grid_capital = [0f64; GRID_CAPITAL];

    for (i, val) in grid_capital.iter_mut().enumerate() {
        *val = 0.5 * capital_steady_state + 0.00001 * (i as f64)
    }

    // 3. Required matrices and vectors
    let mut values: [Vec<f64>; GRID_PRODUCTIVITY] = [
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
    ];

    let mut policies: [Vec<f64>; GRID_PRODUCTIVITY] = [
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
    ];

    let mut expected_values: [Vec<f64>; GRID_PRODUCTIVITY] = [
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
        vec![0f64; GRID_CAPITAL],
    ];

    // 4. We pre-build output for each point in the grid
    let outputs: [Vec<f64>; GRID_PRODUCTIVITY] = [
        (0..GRID_CAPITAL).map(|capital_idx| PRODUCTIVITY[0] * grid_capital[capital_idx].powf(ALPHA)).collect(),
        (0..GRID_CAPITAL).map(|capital_idx| PRODUCTIVITY[1] * grid_capital[capital_idx].powf(ALPHA)).collect(),
        (0..GRID_CAPITAL).map(|capital_idx| PRODUCTIVITY[2] * grid_capital[capital_idx].powf(ALPHA)).collect(),
        (0..GRID_CAPITAL).map(|capital_idx| PRODUCTIVITY[3] * grid_capital[capital_idx].powf(ALPHA)).collect(),
        (0..GRID_CAPITAL).map(|capital_idx| PRODUCTIVITY[4] * grid_capital[capital_idx].powf(ALPHA)).collect(),
    ];

    // 5. Main iteration
    const TOLERANCE: f64 = 0.0000001; // compiler warn: variable does not need to be mutable

    let mut iteration = 0;
    let mut finished = false;

    // small array to split where the writes are going, so we don't need a mutex
    let mut diffs = [-100000.0; GRID_PRODUCTIVITY];

    while !finished {
        pool.scoped(|scoped| {
            for (expected_values, transitions) in expected_values.iter_mut()
                                                                 .zip(TRANSITIONS.iter()) {
                // Only capture refs
                let values = &values;

                scoped.execute(move || {
                    for (idx, expected_value) in expected_values.iter_mut().enumerate() {
                        *expected_value = transitions.iter()
                                                     .zip(values.iter())
                                                     .fold(0.0f64, |acc, (transition, value_fns)| {
                            acc + (transition * value_fns[idx])
                        });
                    }
                });
            }
        });

        pool.scoped(|scoped| {
            for ((((policies, value_fns), max_diff), expected_values), outputs) in policies.iter_mut()
                                                                                .zip(values.iter_mut())
                                                                                .zip(diffs.iter_mut())
                                                                                .zip(expected_values.iter())
                                                                                .zip(outputs.iter()) {
                scoped.execute(move || {
                    *max_diff = -100000.0;

                    // We start from previous choice (monotonicity of policy function)
                    let mut grid_capital_next_period = 0;

                    for ((policy, output), value_fn) in policies.iter_mut()
                                                                .zip(outputs.iter())
                                                                .zip(value_fns.iter_mut()) {
                        let mut value_high = -100000.0;
                        let mut capital_choice = grid_capital[0];

                        for capital_next_period in grid_capital_next_period..GRID_CAPITAL {
                            let consumption = output - &grid_capital[capital_next_period];
                            let value_provisional = (1.0 - BETA) * (consumption.ln()) +
                                                    BETA *
                                                    expected_values[capital_next_period];

                            if value_provisional > value_high {
                                value_high = value_provisional;
                                capital_choice = grid_capital[capital_next_period];
                                grid_capital_next_period = capital_next_period;
                            } else {
                                break; // We break when we have achieved the max
                            }
                        }

                        let old = mem::replace(value_fn, value_high);
                        let diff = (old - value_high).abs();
                        if diff > *max_diff {
                            *max_diff = diff
                        }

                        *policy = capital_choice;
                    }
                })
            }
        });

        let mut max_diff = diffs[0];
        for &diff in &diffs[1..] {
            if diff > max_diff {
                max_diff = diff
            }
        }

        finished = max_diff <= TOLERANCE;

        iteration += 1;
        if print && (iteration % 10 == 0 || iteration == 1 || finished) {
            println!("Iteration = {}, Sup Diff = {}", iteration, max_diff);
        }
    }

    policies[2][999]
}

fn main() {
    use std::env::args;

    let sample = args().any(|arg| arg == "--sample");
    let thread_count = num_cpus::get();
    let ref mut pool = Pool::new(thread_count as u32);

    if sample {
        let mut samples = (0..5).map(|i| {
            let cpu0 = precise_time_s();
            let result = solve(pool, false);
            let cpu1 = precise_time_s();

            assert_eq!(result, 0.1465491436956954);

            let diff = cpu1 - cpu0;
            println!("Sample #{}, Time: {}s", i + 1, diff);
            diff
        }).collect::<Vec<f64>>();

        samples.sort_by(|a, b| a.partial_cmp(b).unwrap());
        println!("\nMedian time is = {}", samples[2]);
    } else {
        let cpu0 = precise_time_s();
        let result = solve(pool, true);
        let cpu1 = precise_time_s();

        println!("My check = {}\n", result);
        assert_eq!(result, 0.1465491436956954);
        println!("Elapsed time is = {}", cpu1 - cpu0);
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::states::actor;
use actix_web::{http::StatusCode, web, HttpRequest, HttpResponse, Responder};
use sdk::api;
use slog_scope::debug;
use thiserror::Error;

pub(crate) struct API(actix::Addr<actor::Machine>);

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, Error)]
pub enum Error {
    #[error("Mailbox error: {0}")]
    ActixMailbox(#[from] actix::MailboxError),
}

impl API {
    pub(crate) fn configure(cfg: &mut web::ServiceConfig, addr: actix::Addr<actor::Machine>) {
        cfg.data(Self(addr))
            .route("/info", web::get().to(API::info))
            .route("/log", web::get().to(API::log))
            .route("/probe", web::post().to(API::probe))
            .route("/local_install", web::post().to(API::local_install))
            .route("/remote_install", web::post().to(API::remote_install))
            .route("/update/download/abort", web::post().to(API::download_abort));
    }

    async fn info(agent: web::Data<API>) -> Result<HttpResponse> {
        debug!("Receiving info request");
        Ok(HttpResponse::Ok().json(agent.0.send(actor::info::Request).await?))
    }

    async fn probe(
        agent: web::Data<API>,
        server_address: Option<web::Json<api::probe::Request>>,
    ) -> Result<actor::probe::Response> {
        let server_address = server_address.map(|r| r.into_inner().custom_server);
        debug!("Receiving probe request with {:?}", server_address);
        Ok(agent.0.send(actor::probe::Request(server_address)).await?)
    }

    async fn local_install(
        agent: web::Data<API>,
        file_path: String,
    ) -> Result<actor::local_install::Response> {
        debug!("Receiving local_install request with {:?}", file_path);
        Ok(agent.0.send(actor::local_install::Request(std::path::PathBuf::from(file_path))).await?)
    }

    async fn remote_install(
        agent: web::Data<API>,
        url: String,
    ) -> Result<actor::remote_install::Response> {
        debug!("Receiving remote_install request with {:?}", url);
        Ok(agent.0.send(actor::remote_install::Request(url)).await?)
    }

    async fn log() -> HttpResponse {
        debug!("Receiving log request");
        HttpResponse::Ok().json(crate::logger::buffer())
    }

    async fn download_abort(agent: web::Data<API>) -> Result<actor::download_abort::Response> {
        debug!("Receiving abort download request");
        Ok(agent.0.send(actor::download_abort::Request).await?)
    }
}

impl Responder for actor::download_abort::Response {
    type Error = actix_web::Error;
    type Future = HttpResponse;

    fn respond_to(self, _: &HttpRequest) -> Self::Future {
        match self {
            actor::download_abort::Response::RequestAccepted => {
                HttpResponse::Ok().json(api::abort_download::Response {
                    message: "request accepted, download aborted".to_owned(),
                })
            }
            actor::download_abort::Response::InvalidState => {
                HttpResponse::BadRequest().json(api::abort_download::Refused {
                    error: "there is no download to be aborted".to_owned(),
                })
            }
        }
    }
}

impl Responder for actor::probe::Response {
    type Error = actix_web::Error;
    type Future = HttpResponse;

    fn respond_to(self, _: &HttpRequest) -> Self::Future {
        match self {
            actor::probe::Response::RequestAccepted(current_state) => {
                HttpResponse::Ok().json(api::state::Response { busy: false, current_state })
            }
            actor::probe::Response::InvalidState(current_state) => {
                HttpResponse::Ok().json(api::state::Response { busy: true, current_state })
            }
        }
    }
}

impl Responder for actor::local_install::Response {
    type Error = actix_web::Error;
    type Future = HttpResponse;

    fn respond_to(self, _: &HttpRequest) -> Self::Future {
        match self {
            actor::local_install::Response::RequestAccepted(current_state) => {
                HttpResponse::Ok().json(api::state::Response { busy: false, current_state })
            }
            actor::local_install::Response::InvalidState(current_state) => {
                HttpResponse::UnprocessableEntity()
                    .json(api::state::Response { busy: true, current_state })
            }
        }
    }
}

impl Responder for actor::remote_install::Response {
    type Error = actix_web::Error;
    type Future = HttpResponse;

    fn respond_to(self, _: &HttpRequest) -> Self::Future {
        match self {
            actor::remote_install::Response::RequestAccepted(current_state) => {
                HttpResponse::Ok().json(api::state::Response { busy: false, current_state })
            }
            actor::remote_install::Response::InvalidState(current_state) => {
                HttpResponse::UnprocessableEntity()
                    .json(api::state::Response { busy: true, current_state })
            }
        }
    }
}

impl actix_web::ResponseError for Error {
    fn status_code(&self) -> StatusCode {
        StatusCode::INTERNAL_SERVER_ERROR
    }

    fn error_response(&self) -> HttpResponse {
        HttpResponse::InternalServerError().finish()
    }
}
<commit_msg>updatehub: Unexpose http_api internal error<commit_after>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::states::actor;
use actix_web::{http::StatusCode, web, HttpRequest, HttpResponse, Responder};
use sdk::api;
use slog_scope::debug;
use thiserror::Error;

pub(crate) struct API(actix::Addr<actor::Machine>);

pub(crate) type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, Error)]
pub(crate) enum Error {
    #[error("Mailbox error: {0}")]
    ActixMailbox(#[from] actix::MailboxError),
}

impl API {
    pub(crate) fn configure(cfg: &mut web::ServiceConfig, addr: actix::Addr<actor::Machine>) {
        cfg.data(Self(addr))
            .route("/info", web::get().to(API::info))
            .route("/log", web::get().to(API::log))
            .route("/probe", web::post().to(API::probe))
            .route("/local_install", web::post().to(API::local_install))
            .route("/remote_install", web::post().to(API::remote_install))
            .route("/update/download/abort", web::post().to(API::download_abort));
    }

    async fn info(agent: web::Data<API>) -> Result<HttpResponse> {
        debug!("Receiving info request");
        Ok(HttpResponse::Ok().json(agent.0.send(actor::info::Request).await?))
    }

    async fn probe(
        agent: web::Data<API>,
        server_address: Option<web::Json<api::probe::Request>>,
    ) -> Result<actor::probe::Response> {
        let server_address = server_address.map(|r| r.into_inner().custom_server);
        debug!("Receiving probe request with {:?}", server_address);
        Ok(agent.0.send(actor::probe::Request(server_address)).await?)
    }

    async fn local_install(
        agent: web::Data<API>,
        file_path: String,
    ) -> Result<actor::local_install::Response> {
        debug!("Receiving local_install request with {:?}", file_path);
        Ok(agent.0.send(actor::local_install::Request(std::path::PathBuf::from(file_path))).await?)
    }

    async fn remote_install(
        agent: web::Data<API>,
        url: String,
    ) -> Result<actor::remote_install::Response> {
        debug!("Receiving remote_install request with {:?}", url);
        Ok(agent.0.send(actor::remote_install::Request(url)).await?)
    }

    async fn log() -> HttpResponse {
        debug!("Receiving log request");
        HttpResponse::Ok().json(crate::logger::buffer())
    }

    async fn download_abort(agent: web::Data<API>) -> Result<actor::download_abort::Response> {
        debug!("Receiving abort download request");
        Ok(agent.0.send(actor::download_abort::Request).await?)
    }
}

impl Responder for actor::download_abort::Response {
    type Error = actix_web::Error;
    type Future = HttpResponse;

    fn respond_to(self, _: &HttpRequest) -> Self::Future {
        match self {
            actor::download_abort::Response::RequestAccepted => {
                HttpResponse::Ok().json(api::abort_download::Response {
                    message: "request accepted, download aborted".to_owned(),
                })
            }
            actor::download_abort::Response::InvalidState => {
                HttpResponse::BadRequest().json(api::abort_download::Refused {
                    error: "there is no download to be aborted".to_owned(),
                })
            }
        }
    }
}

impl Responder for actor::probe::Response {
    type Error = actix_web::Error;
    type Future = HttpResponse;

    fn respond_to(self, _: &HttpRequest) -> Self::Future {
        match self {
            actor::probe::Response::RequestAccepted(current_state) => {
                HttpResponse::Ok().json(api::state::Response { busy: false, current_state })
            }
            actor::probe::Response::InvalidState(current_state) => {
                HttpResponse::Ok().json(api::state::Response { busy: true, current_state })
            }
        }
    }
}

impl Responder for actor::local_install::Response {
    type Error = actix_web::Error;
    type Future = HttpResponse;

    fn respond_to(self, _: &HttpRequest) -> Self::Future {
        match self {
            actor::local_install::Response::RequestAccepted(current_state) => {
                HttpResponse::Ok().json(api::state::Response { busy: false, current_state })
            }
            actor::local_install::Response::InvalidState(current_state) => {
                HttpResponse::UnprocessableEntity()
                    .json(api::state::Response { busy: true, current_state })
            }
        }
    }
}

impl Responder for actor::remote_install::Response {
    type Error = actix_web::Error;
    type Future = HttpResponse;

    fn respond_to(self, _: &HttpRequest) -> Self::Future {
        match self {
            actor::remote_install::Response::RequestAccepted(current_state) => {
                HttpResponse::Ok().json(api::state::Response { busy: false, current_state })
            }
            actor::remote_install::Response::InvalidState(current_state) => {
                HttpResponse::UnprocessableEntity()
                    .json(api::state::Response { busy: true, current_state })
            }
        }
    }
}

impl actix_web::ResponseError for Error {
    fn status_code(&self) -> StatusCode {
        StatusCode::INTERNAL_SERVER_ERROR
    }

    fn error_response(&self) -> HttpResponse {
        HttpResponse::InternalServerError().finish()
    }
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/reachable-nodes-with-restrictions/
pub fn reachable_nodes(n: i32, edges: Vec<Vec<i32>>, restricted: Vec<i32>) -> i32 {
    todo!()
}

fn main() {
    println!(
        "{}",
        reachable_nodes(
            7,
            vec![
                vec![0, 1],
                vec![1, 2],
                vec![3, 1],
                vec![4, 0],
                vec![0, 5],
                vec![5, 6]
            ],
            vec![4, 5]
        )
    ); // 4
    println!(
        "{}",
        reachable_nodes(
            7,
            vec![
                vec![0, 1],
                vec![0, 2],
                vec![0, 5],
                vec![0, 4],
                vec![3, 2],
                vec![6, 5]
            ],
            vec![4, 2, 1]
        )
    ); // 3
}
<commit_msg>Solve problem 2368<commit_after>use std::collections::HashSet;
use std::iter::FromIterator;

// https://leetcode.com/problems/reachable-nodes-with-restrictions/
pub fn reachable_nodes(n: i32, edges: Vec<Vec<i32>>, restricted: Vec<i32>) -> i32 {
    fn build_adj_list(n: i32, edges: &Vec<Vec<i32>>) -> Vec<Vec<i32>> {
        let mut adj_list = vec![vec![]; n as usize];
        for edge in edges.into_iter() {
            if let Some(v) = adj_list.get_mut(edge[0] as usize) {
                v.push(edge[1]);
            }
            if let Some(v) = adj_list.get_mut(edge[1] as usize) {
                v.push(edge[0]);
            }
        }
        adj_list
    }

    fn num_reachable(
        adj_list: &Vec<Vec<i32>>,
        restricted: &HashSet<i32>,
        visited: &mut HashSet<i32>,
        num: i32,
    ) -> i32 {
        if visited.contains(&num) || restricted.contains(&num) {
            return 0;
        }
        visited.insert(num);
        let mut count = 1;
        for adjacent in adj_list.get(num as usize).unwrap_or(&vec![]) {
            count += num_reachable(adj_list, restricted, visited, *adjacent);
        }
        count
    }

    let adj_list = build_adj_list(n, &edges);
    let restricted: HashSet<i32> = HashSet::from_iter(restricted.into_iter());
    num_reachable(&adj_list, &restricted, &mut HashSet::new(), 0)
}

fn main() {
    println!(
        "{}",
        reachable_nodes(
            7,
            vec![
                vec![0, 1],
                vec![1, 2],
                vec![3, 1],
                vec![4, 0],
                vec![0, 5],
                vec![5, 6]
            ],
            vec![4, 5]
        )
    ); // 4
    println!(
        "{}",
        reachable_nodes(
            7,
            vec![
                vec![0, 1],
                vec![0, 2],
                vec![0, 5],
                vec![0, 4],
                vec![3, 2],
                vec![6, 5]
            ],
            vec![4, 2, 1]
        )
    ); // 3
}
<|endoftext|>


<commit_before>use super::buckets::Buckets;
use super::metric::{Metric, MetricKind};
use std::collections::HashMap;
use std::cmp::Ordering;
use time;

/// Creates derived values from metric data.
///
/// Creates:
///
/// - timer percentile data.
/// - internal processing metrics
pub fn process(buckets: &mut Buckets) {
    let start_time = time::get_time();

    let mut timer_data = HashMap::new();

    // Add the various derived values for timers.
    for (key, values) in buckets.timers().iter() {
        let mut v = values.clone();
        v.sort_by(|a, b| a.partial_cmp(b).unwrap());

        let len = v.len() as f64;
        let sum = v.iter().fold(0.0, |sum, x| sum + x);
        let mean = sum / len;

        let mid = (len / 2.0).floor() as usize;
        let median = if (v.len() % 2) == 0 {
            (v[mid - 1] + v[mid + 1]) / 2.0
        } else {
            v[mid]
        };

        // Get population standard deviation
        let sum_diff = v.iter().fold(0.0, |sum, x| sum + (x - mean).powi(2));
        let stddev = (sum_diff / len).sqrt();

        timer_data.insert(format!("{}.min", key), v[0]);
        timer_data.insert(format!("{}.max", key), v[v.len() - 1]);
        timer_data.insert(format!("{}.count", key), len);
        timer_data.insert(format!("{}.mean", key), mean);
        timer_data.insert(format!("{}.median", key), median);
        timer_data.insert(format!("{}.stddev", key), stddev);
    }
    buckets.set_timer_data(timer_data);

    let duration = time::get_time() - start_time;
    let process_duration = Metric::new(
        "statsd.processing_time",
        duration.num_milliseconds() as f64,
        MetricKind::Counter(1.0));
    buckets.add(&process_duration);
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::buckets::Buckets;
    use super::super::metric::{Metric, MetricKind};
    use std::option::Option;
    use time;

    fn make_buckets() -> Buckets {
        let mut buckets = Buckets::new();

        let metrics = [
            Metric::new("some.timer", 13.1, MetricKind::Timer),
            Metric::new("some.timer", 33.7, MetricKind::Timer),
            Metric::new("some.timer", 3.4, MetricKind::Timer),
            Metric::new("some.timer", 12.1, MetricKind::Timer),
        ];
        for m in metrics.iter() {
            buckets.add(&m);
        }
        buckets
    }

    fn assert_float(expected: &str, value: &f64) {
        assert_eq!(expected, format!("{:.*}", 3, value));
    }

    #[test]
    fn test_process_timer_data() {
        let mut buckets = make_buckets();
        process(&mut buckets);

        assert_eq!(Some(&3.4), buckets.timer_data().get("some.timer.min"));
        assert_eq!(Some(&33.7), buckets.timer_data().get("some.timer.max"));
        assert_eq!(Some(&4.0), buckets.timer_data().get("some.timer.count"));
        assert_float(
            "15.575",
            buckets.timer_data().get("some.timer.mean").unwrap());
        assert_float(
            "22.900",
            buckets.timer_data().get("some.timer.median").unwrap());
        assert_float(
            "11.124",
            buckets.timer_data().get("some.timer.stddev").unwrap());
    }

    #[test]
    fn test_set_internal_metrics() {
    }
}
<commit_msg>Add 95th%tile.<commit_after>use super::buckets::Buckets;
use super::metric::{Metric, MetricKind};
use std::collections::HashMap;
use std::cmp::Ordering;
use time;

/// Creates derived values from metric data.
///
/// Creates:
///
/// - timer percentile data.
/// - internal processing metrics
pub fn process(buckets: &mut Buckets) {
    let start_time = time::get_time();

    let mut timer_data = HashMap::new();

    // Add the various derived values for timers.
    for (key, values) in buckets.timers().iter() {
        let mut v = values.clone();
        v.sort_by(|a, b| a.partial_cmp(b).unwrap());

        let len = v.len() as f64;
        let sum = v.iter().fold(0.0, |sum, x| sum + x);
        let mean = sum / len;

        // Get population standard deviation
        let sum_diff = v.iter().fold(0.0, |sum, x| sum + (x - mean).powi(2));
        let stddev = (sum_diff / len).sqrt();

        let median = percentile(&v, 0.5);
        let upper_95 = percentile(&v, 0.95);

        timer_data.insert(format!("{}.min", key), v[0]);
        timer_data.insert(format!("{}.max", key), v[v.len() - 1]);
        timer_data.insert(format!("{}.count", key), len);
        timer_data.insert(format!("{}.mean", key), mean);
        timer_data.insert(format!("{}.median", key), median);
        timer_data.insert(format!("{}.stddev", key), stddev);
        timer_data.insert(format!("{}.upper_95", key), upper_95);
    }
    buckets.set_timer_data(timer_data);

    let duration = time::get_time() - start_time;
    let process_duration = Metric::new(
        "statsd.processing_time",
        duration.num_milliseconds() as f64,
        MetricKind::Counter(1.0));
    buckets.add(&process_duration);
}

fn percentile(values :&Vec<f64>, tile: f64) -> f64 {
    let len = values.len() as f64;
    let index = (len * tile) as usize;
    if (values.len() % 2) == 0 {
        return (values[index - 1] + values[index]) / 2.0;
    } else {
        return values[index];
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::buckets::Buckets;
    use super::super::metric::{Metric, MetricKind};
    use std::option::Option;
    use time;

    fn make_buckets() -> Buckets {
        let mut buckets = Buckets::new();

        let metrics = [
            Metric::new("some.timer", 13.1, MetricKind::Timer),
            Metric::new("some.timer", 33.7, MetricKind::Timer),
            Metric::new("some.timer", 3.4, MetricKind::Timer),
            Metric::new("some.timer", 12.1, MetricKind::Timer),
        ];
        for m in metrics.iter() {
            buckets.add(&m);
        }
        buckets
    }

    fn assert_float(expected: &str, value: &f64) {
        assert_eq!(expected, format!("{:.*}", 3, value));
    }

    #[test]
    fn test_process_timer_data() {
        let mut buckets = make_buckets();
        process(&mut buckets);

        assert_eq!(Some(&3.4), buckets.timer_data().get("some.timer.min"));
        assert_eq!(Some(&33.7), buckets.timer_data().get("some.timer.max"));
        assert_eq!(Some(&4.0), buckets.timer_data().get("some.timer.count"));
        assert_float(
            "15.575",
            buckets.timer_data().get("some.timer.mean").unwrap());
        assert_float(
            "12.600",
            buckets.timer_data().get("some.timer.median").unwrap());
        assert_float(
            "11.124",
            buckets.timer_data().get("some.timer.stddev").unwrap());
        assert_float(
            "23.400",
            buckets.timer_data().get("some.timer.upper_95").unwrap());
    }

    #[test]
    fn test_set_internal_metrics() {
    }
}
<|endoftext|>


<commit_before>#![no_main]
use libfuzzer_sys::fuzz_target;
use std::io::{Error, Read, Write};
use std::process::{Command, Stdio};

use jpeg_decoder::Decoder;
use image::ImageDecoder;

// Try to check the image, never panic.
fn soft_check(data: &[u8]) -> Result<Vec<u8>, Error> {
    let mut check = Command::new("djpeg")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()?;

    {
        let mut stdin = match check.stdin.take() {
            None => return Err(Error::from(std::io::ErrorKind::Other)),
            Some(stdin) => stdin,
        };

        stdin.write_all(data)?;
        stdin.flush()?;
    }

    let output = check.wait_with_output()?;
    if !output.status.success() {
        return Err(Error::from(std::io::ErrorKind::Other));
    }

    let decoder = match image::pnm::PnmDecoder::new(output.stdout.as_slice()) {
        Err(_) => return Err(Error::from(std::io::ErrorKind::Other)),
        Ok(decoder) => decoder,
    };

    let mut image = vec![];
    match decoder.into_reader() {
        Err(_) => return Err(Error::from(std::io::ErrorKind::Other)),
        Ok(mut reader) => match reader.read_to_end(&mut image) {
            Err(_) => return Err(Error::from(std::io::ErrorKind::Other)),
            Ok(_) => {},
        }
    }

    Ok(image)
}

fn roughly(data: &[u8], reference: &[u8]) -> bool {
    data.len() == reference.len() && data
        .iter()
        .zip(reference)
        .all(|(&o, &r)| {
            // Same criterion as in ref test
            (o as i16 - r as i16).abs() <= 2
        })
}

fuzz_target!(|data: &[u8]| {
    // The case should now be fixed.
    let ours = match Decoder::new(data).decode() {
        Err(_) => return,
        Ok(ours) => ours,
    };

    // It should decode correctly.
    let reference = match soft_check(data) {
        Err(_) => return, // Don't crash if it's not a jpeg.
        Ok(reference) => reference,
    };

    if roughly(&ours, &reference) {
        return;
    }

    let mut decoder = previous::Decoder::new(data);
    match decoder.decode() {
        // Oh no, it already decode previously
        Ok(data) if roughly(&data, &reference) => return,
        _ => panic!("Success"),
    }
});
<commit_msg>Repurpose fail_tmin into a fail finder<commit_after>#![no_main]
use libfuzzer_sys::fuzz_target;
use std::io::{Error, Read, Write};
use std::process::{Command, Stdio};

use jpeg_decoder::Decoder;
use image::ImageDecoder;

// Try to check the image, never panic.
fn soft_check(data: &[u8]) -> Result<Vec<u8>, Error> {
    let mut check = Command::new("djpeg")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()?;

    {
        let mut stdin = match check.stdin.take() {
            None => return Err(Error::from(std::io::ErrorKind::Other)),
            Some(stdin) => stdin,
        };

        stdin.write_all(data)?;
        stdin.flush()?;
    }

    let output = check.wait_with_output()?;
    if !output.status.success() {
        return Err(Error::from(std::io::ErrorKind::Other));
    }

    let decoder = match image::pnm::PnmDecoder::new(output.stdout.as_slice()) {
        Err(_) => return Err(Error::from(std::io::ErrorKind::Other)),
        Ok(decoder) => decoder,
    };

    let mut image = vec![];
    match decoder.into_reader() {
        Err(_) => return Err(Error::from(std::io::ErrorKind::Other)),
        Ok(mut reader) => match reader.read_to_end(&mut image) {
            Err(_) => return Err(Error::from(std::io::ErrorKind::Other)),
            Ok(_) => {},
        }
    }

    Ok(image)
}

fn roughly(data: &[u8], reference: &[u8]) -> bool {
    data.len() == reference.len() && data
        .iter()
        .zip(reference)
        .all(|(&o, &r)| {
            // Same criterion as in ref test
            (o as i16 - r as i16).abs() <= 2
        })
}

fuzz_target!(|data: &[u8]| {
    let mut decoder = previous::Decoder::new(data);
    let wrong = decoder.decode().ok();

    // The case should now be fixed.
    let ours = match Decoder::new(data).decode() {
        Err(_) => return,
        Ok(ours) => ours,
    };

    // It should decode correctly.
    let reference = match soft_check(data) {
        Err(_) => return, // Don't crash if it's not a jpeg.
        Ok(reference) => reference,
    };

    // It must now pass the reftest
    if !roughly(&ours, &reference) {
        return;
    }

    // The case must have previously failed to decode, or failed reftest
    match wrong {
        Some(data) if roughly(&data, &reference) => return,
        _ => {},
    }

    panic!("Success")
});
<|endoftext|>


<commit_before>use rand::{
    distributions::{Distribution, Standard},
    seq::SliceRandom,
    Rng, SeedableRng,
};
use rand_xorshift::XorShiftRng;
use reduce::Reduce;
use std::fmt;

const TABLE_SIZE: usize = 256;

pub trait NoiseHasher<T>: Send + Sync {
    fn hash(&self, to_hash: &[T]) -> usize;
}

/// A seed table, required by all noise functions.
///
/// Table creation is expensive, so in most circumstances you'll only want to
/// create one of these per generator.
#[derive(Copy, Clone)]
pub struct PermutationTable {
    values: [u8; TABLE_SIZE],
}

impl Distribution<PermutationTable> for Standard {
    /// Generates a PermutationTable using a random seed.
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> PermutationTable {
        let mut seq: Vec<u8> = (0..TABLE_SIZE).map(|x| x as u8).collect();
        seq.shuffle(rng);

        // It's unfortunate that this double-initializes the array, but Rust
        // doesn't currently provide a clean way to do this in one pass. Hopefully
        // it won't matter, as Seed creation will usually be a one-time event.
        let mut perm_table = PermutationTable {
            values: [0; TABLE_SIZE],
        };
        let seq_it = seq.iter();
        for (x, y) in perm_table.values.iter_mut().zip(seq_it) {
            *x = *y
        }
        perm_table
    }
}

impl PermutationTable {
    /// Deterministically generates a new permutation table based on a `u32` seed value.
    ///
    /// Internally this uses a `XorShiftRng`, but we don't really need to worry
    /// about cryptographic security when working with procedural noise.
    pub fn new(seed: u32) -> Self {
        let mut real = [0; 16];
        real[0] = 1;
        for i in 1..4 {
            real[i * 4] = seed as u8;
            real[(i * 4) + 1] = (seed >> 8) as u8;
            real[(i * 4) + 2] = (seed >> 16) as u8;
            real[(i * 4) + 3] = (seed >> 24) as u8;
        }
        let mut rng: XorShiftRng = SeedableRng::from_seed(real);
        rng.gen()
    }

    pub fn get1(&self, x: isize) -> usize {
        let x = (x & 0xff) as usize;
        self.values[x] as usize
    }

    pub fn get2(&self, pos: [isize; 2]) -> usize {
        let y = (pos[1] & 0xff) as usize;
        self.values[self.get1(pos[0]) ^ y] as usize
    }

    pub fn get3(&self, pos: [isize; 3]) -> usize {
        let z = (pos[2] & 0xff) as usize;
        self.values[self.get2([pos[0], pos[1]]) ^ z] as usize
    }

    pub fn get4(&self, pos: [isize; 4]) -> usize {
        let w = (pos[3] & 0xff) as usize;
        self.values[self.get3([pos[0], pos[1], pos[2]]) ^ w] as usize
    }
}

impl NoiseHasher<isize> for PermutationTable {
    fn hash(&self, to_hash: &[isize]) -> usize {
        let index: usize = to_hash
            .iter()
            .map(|&a| (a & 0xff) as usize)
            .reduce(|a, b| (self.values[a] as usize ^ b))
            .unwrap();
        self.values[index] as usize
    }
}

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

#[cfg(test)]
mod tests {
    use crate::{NoiseFn, Perlin, Seedable};
    use rand::random;

    #[test]
    fn test_random_seed() {
        let perlin = Perlin::new().set_seed(random());
        let _ = perlin.get([1.0, 2.0, 3.0]);
    }

    #[test]
    fn test_negative_params() {
        let perlin = Perlin::new();
        let _ = perlin.get([-1.0, 2.0, 3.0]);
    }
}
<commit_msg>Remove generic tag from Noisehasher<commit_after>use rand::{
    distributions::{Distribution, Standard},
    seq::SliceRandom,
    Rng, SeedableRng,
};
use rand_xorshift::XorShiftRng;
use reduce::Reduce;
use std::fmt;

const TABLE_SIZE: usize = 256;

pub trait NoiseHasher: Send + Sync {
    fn hash(&self, to_hash: &[isize]) -> usize;
}

/// A seed table, required by all noise functions.
///
/// Table creation is expensive, so in most circumstances you'll only want to
/// create one of these per generator.
#[derive(Copy, Clone)]
pub struct PermutationTable {
    values: [u8; TABLE_SIZE],
}

impl Distribution<PermutationTable> for Standard {
    /// Generates a PermutationTable using a random seed.
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> PermutationTable {
        let mut seq: Vec<u8> = (0..TABLE_SIZE).map(|x| x as u8).collect();
        seq.shuffle(rng);

        // It's unfortunate that this double-initializes the array, but Rust
        // doesn't currently provide a clean way to do this in one pass. Hopefully
        // it won't matter, as Seed creation will usually be a one-time event.
        let mut perm_table = PermutationTable {
            values: [0; TABLE_SIZE],
        };
        let seq_it = seq.iter();
        for (x, y) in perm_table.values.iter_mut().zip(seq_it) {
            *x = *y
        }
        perm_table
    }
}

impl PermutationTable {
    /// Deterministically generates a new permutation table based on a `u32` seed value.
    ///
    /// Internally this uses a `XorShiftRng`, but we don't really need to worry
    /// about cryptographic security when working with procedural noise.
    pub fn new(seed: u32) -> Self {
        let mut real = [0; 16];
        real[0] = 1;
        for i in 1..4 {
            real[i * 4] = seed as u8;
            real[(i * 4) + 1] = (seed >> 8) as u8;
            real[(i * 4) + 2] = (seed >> 16) as u8;
            real[(i * 4) + 3] = (seed >> 24) as u8;
        }
        let mut rng: XorShiftRng = SeedableRng::from_seed(real);
        rng.gen()
    }

    pub fn get1(&self, x: isize) -> usize {
        let x = (x & 0xff) as usize;
        self.values[x] as usize
    }

    pub fn get2(&self, pos: [isize; 2]) -> usize {
        let y = (pos[1] & 0xff) as usize;
        self.values[self.get1(pos[0]) ^ y] as usize
    }

    pub fn get3(&self, pos: [isize; 3]) -> usize {
        let z = (pos[2] & 0xff) as usize;
        self.values[self.get2([pos[0], pos[1]]) ^ z] as usize
    }

    pub fn get4(&self, pos: [isize; 4]) -> usize {
        let w = (pos[3] & 0xff) as usize;
        self.values[self.get3([pos[0], pos[1], pos[2]]) ^ w] as usize
    }
}

impl NoiseHasher for PermutationTable {
    fn hash(&self, to_hash: &[isize]) -> usize {
        let index: usize = to_hash
            .iter()
            .map(|&a| (a & 0xff) as usize)
            .reduce(|a, b| (self.values[a] as usize ^ b))
            .unwrap();
        self.values[index] as usize
    }
}

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

#[cfg(test)]
mod tests {
    use crate::{NoiseFn, Perlin, Seedable};
    use rand::random;

    #[test]
    fn test_random_seed() {
        let perlin = Perlin::new().set_seed(random());
        let _ = perlin.get([1.0, 2.0, 3.0]);
    }

    #[test]
    fn test_negative_params() {
        let perlin = Perlin::new();
        let _ = perlin.get([-1.0, 2.0, 3.0]);
    }
}
<|endoftext|>


<commit_before>use irc::client::prelude::*;

use std::time::Duration;
use std::sync::Mutex;

use time;
use chrono::NaiveDateTime;
use humantime::format_duration;

use plugin::*;

use error::FrippyError;
use error::ErrorKind as FrippyErrorKind;
use failure::Fail;
use failure::ResultExt;

pub mod database;
use self::database::{Database, DbResponse};

macro_rules! try_lock {
    ( $m:expr ) => {
        match $m.lock() {
            Ok(guard) => guard,
            Err(poisoned) => poisoned.into_inner(),
        }
    }
}

#[derive(PluginName, Default)]
pub struct Tell<T: Database> {
    tells: Mutex<T>,
}

impl<T: Database> Tell<T> {
    pub fn new(db: T) -> Tell<T> {
        Tell {
            tells: Mutex::new(db),
        }
    }

    fn tell_command(&self, client: &IrcClient, command: PluginCommand) -> Result<&str, String> {
        if command.tokens.len() < 2 {
            return Err(self.invalid_command(client));
        }

        let receiver = &command.tokens[0];
        let sender = command.source;

        if receiver.eq_ignore_ascii_case(&sender) {
            return Err(String::from("That's your name!"));
        }

        if let Some(channels) = client.list_channels() {
            for channel in channels {
                if let Some(users) = client.list_users(&channel) {
                    if users
                        .iter()
                        .any(|u| u.get_nickname().eq_ignore_ascii_case(&receiver))
                    {
                        return Err(format!("{} is online in another channel.", receiver));
                    }
                }
            }
        }

        let tm = time::now().to_timespec();
        let message = command.tokens[1..].join(" ");
        let tell = database::NewTellMessage {
            sender: &sender,
            receiver: &receiver.to_lowercase(),
            time: NaiveDateTime::from_timestamp(tm.sec, 0u32),
            message: &message,
        };

        match try_lock!(self.tells).insert_tell(&tell) {
            DbResponse::Success => Ok("Got it!"),
            DbResponse::Failed(e) => Err(e.to_string()),
        }
    }

    fn send_tells(&self, client: &IrcClient, receiver: &str) -> ExecutionStatus {
        let mut tells = try_lock!(self.tells);
        if let Some(tell_messages) = tells.get_tells(&receiver.to_lowercase()) {
            for tell in tell_messages {
                let now = Duration::new(time::now().to_timespec().sec as u64, 0);
                let dur = now - Duration::new(tell.time.timestamp() as u64, 0);
                let human_dur = format_duration(dur);

                if let Err(e) = client.send_notice(
                    receiver,
                    &format!(
                        "Tell from {} {} ago: {}",
                        tell.sender, human_dur, tell.message
                    ),
                ) {
                    return ExecutionStatus::Err(e.context(FrippyErrorKind::Connection).into());
                }
                debug!(
                    "Sent {:?} from {:?} to {:?}",
                    tell.message, tell.sender, receiver
                );
            }
        }
        tells.delete_tells(&receiver.to_lowercase());

        ExecutionStatus::Done
    }

    fn invalid_command(&self, client: &IrcClient) -> String {
        format!(
            "Incorrect Command. \
             Send \"{} tell help\" for help.",
            client.current_nickname()
        )
    }

    fn help(&self, client: &IrcClient) -> String {
        format!(
            "usage: {} tell user message\r\n\
             example: {0} tell Foobar Hello!",
            client.current_nickname()
        )
    }
}

impl<T: Database> Plugin for Tell<T> {
    fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus {
        match message.command {
            Command::JOIN(_, _, _) => self.send_tells(client, message.source_nickname().unwrap()),
            _ => ExecutionStatus::Done,
        }
    }

    fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> {
        panic!("Tell should not use threading")
    }

    fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
        if command.tokens.is_empty() {
            return Ok(client
                .send_notice(&command.source, &self.invalid_command(client))
                .context(FrippyErrorKind::Connection)?);
        }

        let sender = command.source.to_owned();

        Ok(match command.tokens[0].as_ref() {
            "help" => client
                .send_notice(&command.source, &self.help(client))
                .context(FrippyErrorKind::Connection),
            _ => match self.tell_command(client, command) {
                Ok(msg) => client
                    .send_notice(&sender, msg)
                    .context(FrippyErrorKind::Connection),
                Err(msg) => client
                    .send_notice(&sender, &msg)
                    .context(FrippyErrorKind::Connection),
            },
        }?)
    }

    fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
        Err(String::from("This Plugin does not implement any commands."))
    }
}

use std::fmt;
impl<T: Database> fmt::Debug for Tell<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Tell {{ ... }}")
    }
}
<commit_msg>Correct error message on tell<commit_after>use irc::client::prelude::*;

use std::time::Duration;
use std::sync::Mutex;

use time;
use chrono::NaiveDateTime;
use humantime::format_duration;

use plugin::*;

use error::FrippyError;
use error::ErrorKind as FrippyErrorKind;
use failure::Fail;
use failure::ResultExt;

pub mod database;
use self::database::{Database, DbResponse};

macro_rules! try_lock {
    ( $m:expr ) => {
        match $m.lock() {
            Ok(guard) => guard,
            Err(poisoned) => poisoned.into_inner(),
        }
    }
}

#[derive(PluginName, Default)]
pub struct Tell<T: Database> {
    tells: Mutex<T>,
}

impl<T: Database> Tell<T> {
    pub fn new(db: T) -> Tell<T> {
        Tell {
            tells: Mutex::new(db),
        }
    }

    fn tell_command(&self, client: &IrcClient, command: PluginCommand) -> Result<&str, String> {
        if command.tokens.len() < 2 {
            return Err(self.invalid_command(client));
        }

        let receiver = &command.tokens[0];
        let sender = command.source;

        if receiver.eq_ignore_ascii_case(&sender) {
            return Err(String::from("That's your name!"));
        }

        if let Some(channels) = client.list_channels() {
            for channel in channels {
                if let Some(users) = client.list_users(&channel) {
                    if users
                        .iter()
                        .any(|u| u.get_nickname().eq_ignore_ascii_case(&receiver))
                    {
                        return Err(format!("{} is currently online.", receiver));
                    }
                }
            }
        }

        let tm = time::now().to_timespec();
        let message = command.tokens[1..].join(" ");
        let tell = database::NewTellMessage {
            sender: &sender,
            receiver: &receiver.to_lowercase(),
            time: NaiveDateTime::from_timestamp(tm.sec, 0u32),
            message: &message,
        };

        match try_lock!(self.tells).insert_tell(&tell) {
            DbResponse::Success => Ok("Got it!"),
            DbResponse::Failed(e) => Err(e.to_string()),
        }
    }

    fn send_tells(&self, client: &IrcClient, receiver: &str) -> ExecutionStatus {
        let mut tells = try_lock!(self.tells);
        if let Some(tell_messages) = tells.get_tells(&receiver.to_lowercase()) {
            for tell in tell_messages {
                let now = Duration::new(time::now().to_timespec().sec as u64, 0);
                let dur = now - Duration::new(tell.time.timestamp() as u64, 0);
                let human_dur = format_duration(dur);

                if let Err(e) = client.send_notice(
                    receiver,
                    &format!(
                        "Tell from {} {} ago: {}",
                        tell.sender, human_dur, tell.message
                    ),
                ) {
                    return ExecutionStatus::Err(e.context(FrippyErrorKind::Connection).into());
                }
                debug!(
                    "Sent {:?} from {:?} to {:?}",
                    tell.message, tell.sender, receiver
                );
            }
        }
        tells.delete_tells(&receiver.to_lowercase());

        ExecutionStatus::Done
    }

    fn invalid_command(&self, client: &IrcClient) -> String {
        format!(
            "Incorrect Command. \
             Send \"{} tell help\" for help.",
            client.current_nickname()
        )
    }

    fn help(&self, client: &IrcClient) -> String {
        format!(
            "usage: {} tell user message\r\n\
             example: {0} tell Foobar Hello!",
            client.current_nickname()
        )
    }
}

impl<T: Database> Plugin for Tell<T> {
    fn execute(&self, client: &IrcClient, message: &Message) -> ExecutionStatus {
        match message.command {
            Command::JOIN(_, _, _) => self.send_tells(client, message.source_nickname().unwrap()),
            _ => ExecutionStatus::Done,
        }
    }

    fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> {
        panic!("Tell should not use threading")
    }

    fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
        if command.tokens.is_empty() {
            return Ok(client
                .send_notice(&command.source, &self.invalid_command(client))
                .context(FrippyErrorKind::Connection)?);
        }

        let sender = command.source.to_owned();

        Ok(match command.tokens[0].as_ref() {
            "help" => client
                .send_notice(&command.source, &self.help(client))
                .context(FrippyErrorKind::Connection),
            _ => match self.tell_command(client, command) {
                Ok(msg) => client
                    .send_notice(&sender, msg)
                    .context(FrippyErrorKind::Connection),
                Err(msg) => client
                    .send_notice(&sender, &msg)
                    .context(FrippyErrorKind::Connection),
            },
        }?)
    }

    fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
        Err(String::from("This Plugin does not implement any commands."))
    }
}

use std::fmt;
impl<T: Database> fmt::Debug for Tell<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Tell {{ ... }}")
    }
}
<|endoftext|>


<commit_before>use hyper;
use hyper::header::UserAgent;
use super::response::Response;
use super::Result;

const REQUESTS_USER_AGENT: &'static str = "requests-rs/0.0.0";

pub fn get(url: &str) -> Result<Response> {
    hyper::Client::new()
        .get(url)
        .header(UserAgent(REQUESTS_USER_AGENT.to_owned()))
        .send()
        .map(Response::from)
}

pub fn post(url: &str) -> Result<Response> {
    hyper::Client::new()
        .post(url)
        .header(UserAgent(REQUESTS_USER_AGENT.to_owned()))
        .send()
        .map(Response::from)
}

pub fn put(url: &str) -> Result<Response> {
    hyper::Client::new()
        .put(url)
        .header(UserAgent(REQUESTS_USER_AGENT.to_owned()))
        .send()
        .map(Response::from)
}

pub fn head(url: &str) -> Result<Response> {
    hyper::Client::new()
        .head(url)
        .header(UserAgent(REQUESTS_USER_AGENT.to_owned()))
        .send()
        .map(Response::from)
}

pub fn delete(url: &str) -> Result<Response> {
    hyper::Client::new()
        .delete(url)
        .header(UserAgent(REQUESTS_USER_AGENT.to_owned()))
        .send()
        .map(Response::from)
}
<commit_msg>Update default UserAgent<commit_after>use hyper;
use hyper::header::UserAgent;
use super::response::Response;
use super::Result;

const DEFAULT_USER_AGENT: &'static str = concat!("requests-rs/", env!("CARGO_PKG_VERSION"));

fn default_user_agent() -> UserAgent {
    UserAgent(DEFAULT_USER_AGENT.to_owned())
}

pub fn get(url: &str) -> Result<Response> {
    hyper::Client::new()
        .get(url)
        .header(default_user_agent())
        .send()
        .map(Response::from)
}

pub fn post(url: &str) -> Result<Response> {
    hyper::Client::new()
        .post(url)
        .header(default_user_agent())
        .send()
        .map(Response::from)
}

pub fn put(url: &str) -> Result<Response> {
    hyper::Client::new()
        .put(url)
        .header(default_user_agent())
        .send()
        .map(Response::from)
}

pub fn head(url: &str) -> Result<Response> {
    hyper::Client::new()
        .head(url)
        .header(default_user_agent())
        .send()
        .map(Response::from)
}

pub fn delete(url: &str) -> Result<Response> {
    hyper::Client::new()
        .delete(url)
        .header(default_user_agent())
        .send()
        .map(Response::from)
}
<|endoftext|>


<commit_before>//! Serializes and deserializes Ardite Schema Definitions from different data
//! formats such as JSON and YAML.

use std::io::BufReader;
use std::fs::File;
use std::path::PathBuf;

use regex::Regex;
use serde_json;
use serde_yaml;

use error::{Error, ErrorCode};
use schema::{Definition, Type, Schema};

mod types;

use schema::serde::types::*;

/// Gets an Ardite Schema Definition from a file. Aims to support mainly the
/// JSON and YAML formats.
pub fn from_file(path: PathBuf) -> Result<Definition, Error> {
  let extension = path.extension().map_or("", |s| s.to_str().unwrap());
  let file = try!(File::open(&path));
  let reader = BufReader::new(file);
  match extension {
    "json" => {
      let definition: SerdeDefinition = try!(serde_json::from_reader(reader));
      Ok(try!(serde_definition_into_definition(definition)))
    },
    "yml" => {
      let definition: SerdeDefinition = try!(serde_yaml::from_reader(reader));
      Ok(try!(serde_definition_into_definition(definition)))
    },
    _ => Err(Error::new(
      ErrorCode::NotAcceptable,
      format!("File extension '{}' cannot be deserialized in '{}'.", extension, path.display()),
      Some("Use a recognizable file extension like '.json' or '.yml'.".to_owned())
    ))
  }
}

/// Transforms the intermediary type into the useful type.
fn serde_definition_into_definition(serde_definition: SerdeDefinition) -> Result<Definition, Error> {
  let mut definition = Definition::new();

  for (key, schema) in serde_definition.types.into_iter() {
    let mut type_ = Type::new(key);
    type_.set_boxed_schema(try!(serde_schema_into_schema(schema)));
    definition.add_type(type_);
  }

  Ok(definition)
}

/// Transforms the intermediary type into the useful type.
fn serde_schema_into_schema(serde_schema: SerdeSchema) -> Result<Box<Schema + 'static>, Error> {
  match serde_schema.type_ {
    Some(type_) => match type_.as_str() {
      "null" => Ok(Box::new(Schema::null())),
      "boolean" => Ok(Box::new(Schema::boolean())),
      type_ @ "number" | type_ @ "integer" => {
        let mut schema = Schema::number();
        if type_ == "integer" { schema.set_multiple_of(1.0); }
        else if let Some(multiple_of) = serde_schema.multiple_of { schema.set_multiple_of(multiple_of); }
        if let Some(minimum) = serde_schema.minimum { schema.set_minimum(minimum); }
        if let Some(maximum) = serde_schema.maximum { schema.set_maximum(maximum); }
        if serde_schema.exclusive_minimum.unwrap_or(false) { schema.enable_exclusive_minimum(); }
        if serde_schema.exclusive_maximum.unwrap_or(false) { schema.enable_exclusive_maximum(); }
        Ok(Box::new(schema))
      },
      "string" => {
        let mut schema = Schema::string();
        if let Some(min_length) = serde_schema.min_length { schema.set_min_length(min_length); }
        if let Some(max_length) = serde_schema.max_length { schema.set_max_length(max_length); }
        if let Some(pattern) = serde_schema.pattern.and_then(|p| Regex::new(&p).ok()) { schema.set_pattern(pattern); }
        Ok(Box::new(schema))
      },
      "array" => {
        let mut schema = Schema::array();
        if let Some(items) = serde_schema.items { schema.set_boxed_items(try!(serde_schema_into_schema(*items))); }
        Ok(Box::new(schema))
      },
      "object" => {
        let mut schema = Schema::object();
        schema.set_required(serde_schema.required.unwrap_or_default());
        if serde_schema.additional_properties.unwrap_or(false) { schema.enable_additional_properties(); }
        for (key, value) in serde_schema.properties.unwrap_or_default() {
          schema.add_boxed_property(key, try!(serde_schema_into_schema(value)));
        }
        Ok(Box::new(schema))
      },
      _ => Err(Error::invalid(
        format!("Invalid type '{}'.", type_),
        format!("Use a permitted type like 'string' and not '{}'.", type_)
      ))
    },
    None => {
      if let Some(enum_) = serde_schema.enum_ {
        Ok(Box::new(Schema::enum_(enum_)))
      } else {
        Err(Error::invalid("No schema type specified.", "Set a `type` property or an `enum` property."))
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use super::from_file;

  use std::path::PathBuf;

  use schema::definition::create_basic;

  #[test]
  fn test_basic_json() {
    assert_eq!(from_file(PathBuf::from("tests/fixtures/definitions/basic.json")).unwrap(), create_basic());
  }

  #[test]
  fn test_basic_yaml() {
    assert_eq!(from_file(PathBuf::from("tests/fixtures/definitions/basic.yml")).unwrap(), create_basic());
  }
}
<commit_msg>style(schema): move mod declaration<commit_after>//! Serializes and deserializes Ardite Schema Definitions from different data
//! formats such as JSON and YAML.

mod types;

use std::io::BufReader;
use std::fs::File;
use std::path::PathBuf;

use regex::Regex;
use serde_json;
use serde_yaml;

use error::{Error, ErrorCode};
use schema::{Definition, Type, Schema};
use schema::serde::types::*;

/// Gets an Ardite Schema Definition from a file. Aims to support mainly the
/// JSON and YAML formats.
pub fn from_file(path: PathBuf) -> Result<Definition, Error> {
  let extension = path.extension().map_or("", |s| s.to_str().unwrap());
  let file = try!(File::open(&path));
  let reader = BufReader::new(file);
  match extension {
    "json" => {
      let definition: SerdeDefinition = try!(serde_json::from_reader(reader));
      Ok(try!(serde_definition_into_definition(definition)))
    },
    "yml" => {
      let definition: SerdeDefinition = try!(serde_yaml::from_reader(reader));
      Ok(try!(serde_definition_into_definition(definition)))
    },
    _ => Err(Error::new(
      ErrorCode::NotAcceptable,
      format!("File extension '{}' cannot be deserialized in '{}'.", extension, path.display()),
      Some("Use a recognizable file extension like '.json' or '.yml'.".to_owned())
    ))
  }
}

/// Transforms the intermediary type into the useful type.
fn serde_definition_into_definition(serde_definition: SerdeDefinition) -> Result<Definition, Error> {
  let mut definition = Definition::new();

  for (key, schema) in serde_definition.types.into_iter() {
    let mut type_ = Type::new(key);
    type_.set_boxed_schema(try!(serde_schema_into_schema(schema)));
    definition.add_type(type_);
  }

  Ok(definition)
}

/// Transforms the intermediary type into the useful type.
fn serde_schema_into_schema(serde_schema: SerdeSchema) -> Result<Box<Schema + 'static>, Error> {
  match serde_schema.type_ {
    Some(type_) => match type_.as_str() {
      "null" => Ok(Box::new(Schema::null())),
      "boolean" => Ok(Box::new(Schema::boolean())),
      type_ @ "number" | type_ @ "integer" => {
        let mut schema = Schema::number();
        if type_ == "integer" { schema.set_multiple_of(1.0); }
        else if let Some(multiple_of) = serde_schema.multiple_of { schema.set_multiple_of(multiple_of); }
        if let Some(minimum) = serde_schema.minimum { schema.set_minimum(minimum); }
        if let Some(maximum) = serde_schema.maximum { schema.set_maximum(maximum); }
        if serde_schema.exclusive_minimum.unwrap_or(false) { schema.enable_exclusive_minimum(); }
        if serde_schema.exclusive_maximum.unwrap_or(false) { schema.enable_exclusive_maximum(); }
        Ok(Box::new(schema))
      },
      "string" => {
        let mut schema = Schema::string();
        if let Some(min_length) = serde_schema.min_length { schema.set_min_length(min_length); }
        if let Some(max_length) = serde_schema.max_length { schema.set_max_length(max_length); }
        if let Some(pattern) = serde_schema.pattern.and_then(|p| Regex::new(&p).ok()) { schema.set_pattern(pattern); }
        Ok(Box::new(schema))
      },
      "array" => {
        let mut schema = Schema::array();
        if let Some(items) = serde_schema.items { schema.set_boxed_items(try!(serde_schema_into_schema(*items))); }
        Ok(Box::new(schema))
      },
      "object" => {
        let mut schema = Schema::object();
        schema.set_required(serde_schema.required.unwrap_or_default());
        if serde_schema.additional_properties.unwrap_or(false) { schema.enable_additional_properties(); }
        for (key, value) in serde_schema.properties.unwrap_or_default() {
          schema.add_boxed_property(key, try!(serde_schema_into_schema(value)));
        }
        Ok(Box::new(schema))
      },
      _ => Err(Error::invalid(
        format!("Invalid type '{}'.", type_),
        format!("Use a permitted type like 'string' and not '{}'.", type_)
      ))
    },
    None => {
      if let Some(enum_) = serde_schema.enum_ {
        Ok(Box::new(Schema::enum_(enum_)))
      } else {
        Err(Error::invalid("No schema type specified.", "Set a `type` property or an `enum` property."))
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use super::from_file;

  use std::path::PathBuf;

  use schema::definition::create_basic;

  #[test]
  fn test_basic_json() {
    assert_eq!(from_file(PathBuf::from("tests/fixtures/definitions/basic.json")).unwrap(), create_basic());
  }

  #[test]
  fn test_basic_yaml() {
    assert_eq!(from_file(PathBuf::from("tests/fixtures/definitions/basic.yml")).unwrap(), create_basic());
  }
}
<|endoftext|>


<commit_before>use bifrost::vector_clock::{StandardVectorClock, Relation};
use std::collections::{BTreeSet, HashMap};
use chashmap::{CHashMap, WriteGuard};
use ram::types::{Id};
use ram::cell::{Cell, ReadError, WriteError};
use server::NebServer;
use super::*;

pub type CellMetaGuard <'a> = WriteGuard<'a, Id, CellMeta>;

pub struct CellMeta {
    read: TransactionId,
    write: TransactionId,
    owner: Option<TransactionId>, // transaction that owns the cell in Committing state
    waiting: BTreeSet<TransactionId>, // transactions that waiting for owner to finish
}

#[derive(Debug, Serialize, Deserialize)]
pub enum CellCommit {
    Write(Cell),
    Update(Cell),
    Remove(Id)
}

#[derive(Debug, Serialize, Deserialize)]
pub enum PrepareResult {
    Wait,
    Success,
    TransactionNotExisted,
    NotRealizable,
}

#[derive(Debug, Eq, PartialEq)]
enum TransactionState {
    Started,
    Aborted,
    Committing,
    Committed
}

struct Transaction {
    server: u64,
    id: TransactionId,
    state: TransactionState
}

pub struct DataManager {
    cells: CHashMap<Id, CellMeta>,
    tnxs: CHashMap<TransactionId, Transaction>,
    server: Arc<NebServer>
}

service! {
    rpc read(server_id: u64, clock: StandardVectorClock, tid: TransactionId, id: Id) -> DataSiteResponse<TransactionExecResult<Cell, ReadError>>;

    // two phase commit
    rpc prepare(clock :StandardVectorClock, tid: TransactionId, cell_ids: Vec<Id>) -> DataSiteResponse<PrepareResult>;
    rpc commit(clock :StandardVectorClock, tid: TransactionId, cells: Vec<CellCommit>) -> DataSiteResponse<bool>;

    rpc abort(clock :StandardVectorClock, tid: TransactionId) -> DataSiteResponse<()>;
}

dispatch_rpc_service_functions!(DataManager);

impl DataManager {
    fn local_clock(&self) -> StandardVectorClock {
        self.server.tnx_peer.clock.to_clock()
    }
    fn update_clock(&self, clock: &StandardVectorClock) {
        self.server.tnx_peer.clock.merge_with(clock);
    }
    fn get_transaction(&self, tid: &TransactionId, server: &u64) -> WriteGuard<TransactionId, Transaction> {
        if !self.tnxs.contains_key(tid) {
            self.tnxs.upsert(tid.clone(), ||{
                Transaction {
                    id: tid.clone(),
                    server: *server,
                    state: TransactionState::Started
                }
            }, |t|{});
        }
        match self.tnxs.get_mut(tid) {
            Some(tnx) => tnx,
            _ => self.get_transaction(tid, server) // it should be rare
        }
    }
    fn get_cell_meta(&self, id: &Id) -> CellMetaGuard {
        if !self.cells.contains_key(id) {
            self.cells.upsert(id.clone(), || {
                CellMeta {
                    read: TransactionId::new(),
                    write: TransactionId::new(),
                    owner: None,
                    waiting: BTreeSet::new()
                }
            }, |c|{});
        }
        match self.cells.get_mut(id) {
            Some(cell) => cell,
            _ => self.get_cell_meta(id)
        }
    }
    fn response_with<T>(&self, data: T)
        -> Result<DataSiteResponse<T>, ()>{
        Ok(DataSiteResponse::new(&self.server.tnx_peer, data))
    }
}

impl Service for DataManager {
    fn read(&self, server_id: &u64, clock: &StandardVectorClock, tid: &TransactionId, id: &Id)
        -> Result<DataSiteResponse<TransactionExecResult<Cell, ReadError>>, ()> {
        self.update_clock(clock);
        let mut tnx = self.get_transaction(tid, server_id);
        let mut meta = self.get_cell_meta(id);
        let committing = meta.owner.is_some();
        let read_too_late = &meta.write > tid;
        if read_too_late { // not realizable
            return self.response_with(TransactionExecResult::Rejected);
        }
        if committing { // ts >= wt but committing, need to wait until it committed
            meta.waiting.insert(tid.clone());
            return self.response_with(TransactionExecResult::Wait);
        }
        let cell = match self.server.chunks.read_cell(id) {
            Ok(cell) => {cell}
            Err(read_error) => {
                // cannot read
                return self.response_with(TransactionExecResult::Error(read_error));
            }
        };
        let update_read = &meta.read < tid;
        if update_read {
            meta.read = tid.clone()
        }
        self.response_with(TransactionExecResult::Accepted(cell))
    }
    fn prepare(&self, clock :&StandardVectorClock, tid: &TransactionId, cell_ids: &Vec<Id>)
        -> Result<DataSiteResponse<PrepareResult>, ()> {
        // In this stage, data manager will not do any write operation but mark cell owner in their meta as a lock
        // It will also check if write are realizable. If not, transaction manager should retry with new id
        // cell_ids must be sorted to avoid deadlock. It can be done from data manager by using BTreeMap keys
        self.update_clock(clock);
        let mut tnx = match self.tnxs.get_mut(tid) {
            Some(tnx) => tnx,
            _ => {
                return self.response_with(PrepareResult::TransactionNotExisted);
            }
        };
        let mut cell_metas: Vec<CellMetaGuard> = Vec::new();
        for cell_id in cell_ids {
            let meta = self.get_cell_meta(cell_id);
            if tid < &meta.read { // write too late
                break;
            }
            if tid < &meta.write {
                if meta.owner.is_some() { // not committed, should wait and try prepare again
                    return self.response_with(PrepareResult::Wait)
                }
            }
            cell_metas.push(meta);
        }
        if cell_metas.len() < cell_ids.len() {
            return self.response_with(PrepareResult::NotRealizable); // need retry
        } else {
            for mut meta in cell_metas {
                meta.owner = Some(tid.clone()) // set owner to lock this cell
            }
            return self.response_with(PrepareResult::Success);
        }
    }
    fn commit(&self, clock :&StandardVectorClock, tid: &TransactionId, cells: &Vec<CellCommit>)
        -> Result<DataSiteResponse<bool>, ()>  {
        self.update_clock(clock);
        unimplemented!()
    }
    fn abort(&self, clock :&StandardVectorClock, tid: &TransactionId)
        -> Result<DataSiteResponse<()>, ()>  {
        self.update_clock(clock);
        unimplemented!()
    }
}<commit_msg>update on trnsaction meta<commit_after>use bifrost::vector_clock::{StandardVectorClock, Relation};
use bifrost::utils::time::get_time;
use std::collections::{BTreeSet, HashMap};
use chashmap::{CHashMap, WriteGuard};
use ram::types::{Id};
use ram::cell::{Cell, ReadError, WriteError};
use server::NebServer;
use super::*;

pub type CellMetaGuard <'a> = WriteGuard<'a, Id, CellMeta>;

pub struct CellMeta {
    read: TransactionId,
    write: TransactionId,
    owner: Option<TransactionId>, // transaction that owns the cell in Committing state
    waiting: BTreeSet<TransactionId>, // transactions that waiting for owner to finish
}

#[derive(Debug, Serialize, Deserialize)]
pub enum CellCommit {
    Write(Cell),
    Update(Cell),
    Remove(Id)
}

#[derive(Debug, Serialize, Deserialize)]
pub enum PrepareResult {
    Wait,
    Success,
    TransactionNotExisted,
    NotRealizable,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum CommitResult {
    Success,
    TransactionNotExisted,
    Error(WriteError),
}

#[derive(Debug, Eq, PartialEq)]
enum TransactionState {
    Started,
    Aborted,
    Committing,
    Committed,
}

struct Transaction {
    server: u64,
    id: TransactionId,
    state: TransactionState,
    affect_cells: u16,
    last_activity: i64,
}

pub struct DataManager {
    cells: CHashMap<Id, CellMeta>,
    tnxs: CHashMap<TransactionId, Transaction>,
    server: Arc<NebServer>
}

service! {
    rpc read(server_id: u64, clock: StandardVectorClock, tid: TransactionId, id: Id) -> DataSiteResponse<TransactionExecResult<Cell, ReadError>>;

    // two phase commit
    rpc prepare(clock :StandardVectorClock, tid: TransactionId, cell_ids: Vec<Id>) -> DataSiteResponse<PrepareResult>;
    rpc commit(clock :StandardVectorClock, tid: TransactionId, cells: Vec<CellCommit>) -> DataSiteResponse<bool>;

    rpc abort(clock :StandardVectorClock, tid: TransactionId) -> DataSiteResponse<()>;
}

dispatch_rpc_service_functions!(DataManager);

impl DataManager {
    fn local_clock(&self) -> StandardVectorClock {
        self.server.tnx_peer.clock.to_clock()
    }
    fn update_clock(&self, clock: &StandardVectorClock) {
        self.server.tnx_peer.clock.merge_with(clock);
    }
    fn get_transaction(&self, tid: &TransactionId, server: &u64) -> WriteGuard<TransactionId, Transaction> {
        if !self.tnxs.contains_key(tid) {
            self.tnxs.upsert(tid.clone(), ||{
                Transaction {
                    id: tid.clone(),
                    server: *server,
                    state: TransactionState::Started,
                    affect_cells: 0,
                    last_activity: get_time()
                }
            }, |t|{});
        }
        match self.tnxs.get_mut(tid) {
            Some(tnx) => tnx,
            _ => self.get_transaction(tid, server) // it should be rare
        }
    }
    fn get_cell_meta(&self, id: &Id) -> CellMetaGuard {
        if !self.cells.contains_key(id) {
            self.cells.upsert(id.clone(), || {
                CellMeta {
                    read: TransactionId::new(),
                    write: TransactionId::new(),
                    owner: None,
                    waiting: BTreeSet::new()
                }
            }, |c|{});
        }
        match self.cells.get_mut(id) {
            Some(cell) => cell,
            _ => self.get_cell_meta(id)
        }
    }
    fn response_with<T>(&self, data: T)
        -> Result<DataSiteResponse<T>, ()>{
        Ok(DataSiteResponse::new(&self.server.tnx_peer, data))
    }
}

impl Service for DataManager {
    fn read(&self, server_id: &u64, clock: &StandardVectorClock, tid: &TransactionId, id: &Id)
        -> Result<DataSiteResponse<TransactionExecResult<Cell, ReadError>>, ()> {
        self.update_clock(clock);
        let mut meta = self.get_cell_meta(id);
        let committing = meta.owner.is_some();
        let read_too_late = &meta.write > tid;
        let mut tnx = self.get_transaction(tid, server_id);
        if read_too_late { // not realizable
            return self.response_with(TransactionExecResult::Rejected);
        }
        if committing { // ts >= wt but committing, need to wait until it committed
            meta.waiting.insert(tid.clone());
            return self.response_with(TransactionExecResult::Wait);
        }
        let cell = match self.server.chunks.read_cell(id) {
            Ok(cell) => {cell}
            Err(read_error) => {
                // cannot read
                return self.response_with(TransactionExecResult::Error(read_error));
            }
        };
        let update_read = &meta.read < tid;
        if update_read {
            meta.read = tid.clone()
        }
        tnx.last_activity = get_time();
        self.response_with(TransactionExecResult::Accepted(cell))
    }
    fn prepare(&self, clock :&StandardVectorClock, tid: &TransactionId, cell_ids: &Vec<Id>)
        -> Result<DataSiteResponse<PrepareResult>, ()> {
        // In this stage, data manager will not do any write operation but mark cell owner in their meta as a lock
        // It will also check if write are realizable. If not, transaction manager should retry with new id
        // cell_ids must be sorted to avoid deadlock. It can be done from data manager by using BTreeMap keys
        self.update_clock(clock);
        let mut tnx = match self.tnxs.get_mut(tid) {
            Some(tnx) => tnx,
            _ => {
                return self.response_with(PrepareResult::TransactionNotExisted);
            }
        };
        let mut cell_metas: Vec<CellMetaGuard> = Vec::new();
        for cell_id in cell_ids {
            let meta = self.get_cell_meta(cell_id);
            if tid < &meta.read { // write too late
                break;
            }
            if tid < &meta.write {
                if meta.owner.is_some() { // not committed, should wait and try prepare again
                    return self.response_with(PrepareResult::Wait)
                }
            }
            cell_metas.push(meta);
        }
        if cell_metas.len() < cell_ids.len() {
            return self.response_with(PrepareResult::NotRealizable); // need retry
        } else {
            for mut meta in cell_metas {
                meta.owner = Some(tid.clone()) // set owner to lock this cell
            }
            tnx.state = TransactionState::Committing;
            tnx.last_activity = get_time();
            return self.response_with(PrepareResult::Success);
        }
    }
    fn commit(&self, clock :&StandardVectorClock, tid: &TransactionId, cells: &Vec<CellCommit>)
        -> Result<DataSiteResponse<bool>, ()>  {
        self.update_clock(clock);

        unimplemented!()

    }
    fn abort(&self, clock :&StandardVectorClock, tid: &TransactionId)
        -> Result<DataSiteResponse<()>, ()>  {
        self.update_clock(clock);
        unimplemented!()
    }
}<|endoftext|>