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

use std::path::{Path, PathBuf};
use std::process::Command;

use devicemapper::{Bytes, DM, DataBlocks, Sectors, ThinDev, ThinDevId, ThinStatus, ThinPoolDev};

use nix::sys::statvfs::*;

use super::super::engine::{Filesystem, HasName, HasUuid};
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::types::FilesystemUuid;

use super::serde_structs::{FilesystemSave, Recordable};

#[derive(Debug)]
pub struct StratFilesystem {
    fs_id: FilesystemUuid,
    name: String,
    thin_dev: ThinDev,
}

pub enum FilesystemStatus {
    Good,
    Failed,
}

impl StratFilesystem {
    /// Create a StratFilesystem on top of the given ThinDev.
    pub fn initialize(fs_id: FilesystemUuid,
                      name: &str,
                      thin_dev: ThinDev)
                      -> EngineResult<StratFilesystem> {
        let fs = StratFilesystem::setup(fs_id, name, thin_dev);

        try!(create_fs(try!(fs.devnode()).as_path()));
        Ok(fs)
    }

    /// Build a StratFilesystem that includes the ThinDev and related info.
    pub fn setup(fs_id: FilesystemUuid, name: &str, thin_dev: ThinDev) -> StratFilesystem {
        StratFilesystem {
            fs_id: fs_id,
            name: name.to_owned(),
            thin_dev: thin_dev,
        }
    }

    pub fn check(&self, dm: &DM) -> EngineResult<FilesystemStatus> {
        match try!(self.thin_dev.status(dm)) {
            ThinStatus::Good((_mapped, _highest)) => {
                // TODO: check if filesystem is getting full and might need to
                // be extended (hint: use statfs(2))
                // TODO: periodically kick off fstrim?
            }
            ThinStatus::Fail => return Ok(FilesystemStatus::Failed),
        }
        Ok(FilesystemStatus::Good)
    }

    /// The thin id for the thin device that backs this filesystem.
    pub fn thin_id(&self) -> ThinDevId {
        self.thin_dev.id()
    }

    /// Get the mount_point for this filesystem
    /// TODO Replace this code with something less brittle
    pub fn get_mount_point(&self) -> EngineResult<PathBuf> {
        let output = try!(Command::new("df")
                              .arg("--output=target")
                              .arg(&try!(self.devnode()))
                              .output());
        if output.status.success() {
            let output_str = String::from_utf8_lossy(&output.stdout);
            match output_str.lines().last() {
                Some(mount_point) => return Ok(PathBuf::from(mount_point)),
                _ => {}
            }
        }
        let err_msg = format!("Failed to get fielsystem mountpoint at {:?}",
                              self.devnode());
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }

    /// Tear down the filesystem.
    pub fn teardown(self, dm: &DM) -> EngineResult<()> {
        Ok(try!(self.thin_dev.teardown(dm)))
    }

    /// Set the name of this filesystem to name.
    pub fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    /// Destroy the filesystem.
    pub fn destroy(self, dm: &DM, thin_pool: &ThinPoolDev) -> EngineResult<()> {
        Ok(try!(self.thin_dev.destroy(dm, thin_pool)))
    }
}

impl HasName for StratFilesystem {
    fn name(&self) -> &str {
        &self.name
    }
}

impl HasUuid for StratFilesystem {
    fn uuid(&self) -> &FilesystemUuid {
        &self.fs_id
    }
}

impl Filesystem for StratFilesystem {
    fn devnode(&self) -> EngineResult<PathBuf> {
        Ok(try!(self.thin_dev.devnode()))
    }
}

impl Recordable<FilesystemSave> for StratFilesystem {
    fn record(&self) -> EngineResult<FilesystemSave> {
        Ok(FilesystemSave {
               name: self.name.clone(),
               uuid: self.fs_id,
               thin_id: self.thin_dev.id(),
               size: self.thin_dev.size(),
           })
    }
}

/// Create a filesystem on devnode.
pub fn create_fs(devnode: &Path) -> EngineResult<()> {
    if try!(Command::new("mkfs.xfs")
                .arg("-f")
                .arg(&devnode)
                .status())
               .success() {
        Ok(())
    } else {
        let err_msg = format!("Failed to create new filesystem at {:?}", devnode);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}
<commit_msg>expand the check() function to look at filesystem usage<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::path::{Path, PathBuf};
use std::process::Command;

use devicemapper::{Bytes, DM, Sectors, ThinDev, ThinDevId, ThinStatus, ThinPoolDev};
use devicemapper::consts::{IEC, SECTOR_SIZE};

use nix::sys::statvfs::statvfs;
use nix::sys::statvfs::vfs::Statvfs;

use super::super::engine::{Filesystem, HasName, HasUuid};
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::types::FilesystemUuid;

use super::serde_structs::{FilesystemSave, Recordable};

/// TODO: confirm that 256 MiB leaves enough time for stratisd to respond and extend before
/// the filesystem is out of space.
pub const FILESYSTEM_LOWATER: Sectors = Sectors(256 * IEC::Mi / (SECTOR_SIZE as u64)); // = 256 MiB

#[derive(Debug)]
pub struct StratFilesystem {
    fs_id: FilesystemUuid,
    name: String,
    thin_dev: ThinDev,
}

pub enum FilesystemStatus {
    Good,
    XfsGrowFailed,
    ThinDevExtendFailed,
    Failed,
}

impl StratFilesystem {
    /// Create a StratFilesystem on top of the given ThinDev.
    pub fn initialize(fs_id: FilesystemUuid,
                      name: &str,
                      thin_dev: ThinDev)
                      -> EngineResult<StratFilesystem> {
        let fs = StratFilesystem::setup(fs_id, name, thin_dev);

        try!(create_fs(try!(fs.devnode()).as_path()));
        Ok(fs)
    }

    /// Build a StratFilesystem that includes the ThinDev and related info.
    pub fn setup(fs_id: FilesystemUuid, name: &str, thin_dev: ThinDev) -> StratFilesystem {
        StratFilesystem {
            fs_id: fs_id,
            name: name.to_owned(),
            thin_dev: thin_dev,
        }
    }

    /// check if filesystem is getting full and needs to be extended
    /// TODO: deal with the thindev in a Fail state.
    pub fn check(&mut self, dm: &DM) -> EngineResult<FilesystemStatus> {
        match try!(self.thin_dev.status(dm)) {
            ThinStatus::Good(_) => {
                let mount_point = try!(self.get_mount_point());
                let (fs_total_bytes, fs_total_used_bytes) = try!(fs_usage(&mount_point));
                let free_bytes = fs_total_bytes - fs_total_used_bytes;
                if free_bytes.sectors() < FILESYSTEM_LOWATER {
                    let extend_size = self.extend_size(self.thin_dev.size());
                    if let Err(_) = self.thin_dev.extend(dm, extend_size) {
                        return Ok(FilesystemStatus::ThinDevExtendFailed);
                    }
                    if let Err(_) = xfs_growfs(&mount_point) {
                        return Ok(FilesystemStatus::XfsGrowFailed);
                    }
                }
                // TODO: periodically kick off fstrim?
            }
            ThinStatus::Fail => return Ok(FilesystemStatus::Failed),
        }
        Ok(FilesystemStatus::Good)
    }

    /// The thin id for the thin device that backs this filesystem.
    pub fn thin_id(&self) -> ThinDevId {
        self.thin_dev.id()
    }

    /// Return an extend size for the thindev under the filesystem
    /// TODO: returning the current size will double the space provisoned to
    /// the thin device.  We should determine if this is a reasonable value.
    fn extend_size(&self, current_size: Sectors) -> Sectors {
        current_size
    }

    /// Get the mount_point for this filesystem
    /// TODO Replace this code with something less brittle
    pub fn get_mount_point(&self) -> EngineResult<PathBuf> {
        let output = try!(Command::new("df")
                              .arg("--output=target")
                              .arg(&try!(self.devnode()))
                              .output());
        if output.status.success() {
            let output_str = String::from_utf8_lossy(&output.stdout);
            if let Some(mount_point) = output_str.lines().last() {
                return Ok(PathBuf::from(mount_point));
            }
        }
        let err_msg = format!("Failed to get filesystem mountpoint at {:?}",
                              self.devnode());
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }

    /// Tear down the filesystem.
    pub fn teardown(self, dm: &DM) -> EngineResult<()> {
        Ok(try!(self.thin_dev.teardown(dm)))
    }

    /// Set the name of this filesystem to name.
    pub fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    /// Destroy the filesystem.
    pub fn destroy(self, dm: &DM, thin_pool: &ThinPoolDev) -> EngineResult<()> {
        Ok(try!(self.thin_dev.destroy(dm, thin_pool)))
    }
}

impl HasName for StratFilesystem {
    fn name(&self) -> &str {
        &self.name
    }
}

impl HasUuid for StratFilesystem {
    fn uuid(&self) -> &FilesystemUuid {
        &self.fs_id
    }
}

impl Filesystem for StratFilesystem {
    fn devnode(&self) -> EngineResult<PathBuf> {
        Ok(try!(self.thin_dev.devnode()))
    }
}

impl Recordable<FilesystemSave> for StratFilesystem {
    fn record(&self) -> EngineResult<FilesystemSave> {
        Ok(FilesystemSave {
               name: self.name.clone(),
               uuid: self.fs_id,
               thin_id: self.thin_dev.id(),
               size: self.thin_dev.size(),
           })
    }
}

/// Return total bytes allocated to the filesystem, total bytes used by data/metadata
pub fn fs_usage(mount_point: &Path) -> EngineResult<(Bytes, Bytes)> {
    let mut stat = Statvfs::default();
    try!(statvfs(mount_point, &mut stat));
    Ok((Bytes(stat.f_bsize * stat.f_blocks), Bytes(stat.f_bsize * (stat.f_blocks - stat.f_bfree))))
}

/// Use the xfs_growfs command to expand a filesystem mounted at the given
/// mount point.
pub fn xfs_growfs(mount_point: &Path) -> EngineResult<()> {
    if try!(Command::new("xfs_growfs")
                .arg(mount_point)
                .arg("-d")
                .status())
               .success() {
        Ok(())
    } else {
        let err_msg = format!("Failed to expand filesystem {:?}", mount_point);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}

/// Create a filesystem on devnode.
pub fn create_fs(devnode: &Path) -> EngineResult<()> {
    if try!(Command::new("mkfs.xfs")
                .arg("-f")
                .arg(&devnode)
                .status())
               .success() {
        Ok(())
    } else {
        let err_msg = format!("Failed to create new filesystem at {:?}", devnode);
        Err(EngineError::Engine(ErrorEnum::Error, err_msg))
    }
}
<|endoftext|>


<commit_before>use std::cmp::min;
use std::thread;
use std::time::Duration;

use indicatif::{ProgressBar, ProgressStyle};

fn main() {
    let mut downloaded = 0;
    let total_size = 231231231;

    let pb = ProgressBar::new(total_size);
    pb.set_style(ProgressStyle::default_bar()
        .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
        .progress_chars("#>-"));

    while downloaded < total_size {
        let new = min(downloaded + 223211, total_size);
        downloaded = new;
        pb.set_position(new);
        thread::sleep(Duration::from_millis(12));
    }

    pb.finish_with_message("downloaded");
}
<commit_msg>Fix example download-speed on 80 width terminal<commit_after>use std::cmp::min;
use std::thread;
use std::time::Duration;

use indicatif::{ProgressBar, ProgressStyle};

fn main() {
    let mut downloaded = 0;
    let total_size = 231231231;

    let pb = ProgressBar::new(total_size);
    pb.set_style(ProgressStyle::default_bar()
        .template("{spinner:.green} [{elapsed_precise}] [{bar:30.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
        .progress_chars("#>-"));

    while downloaded < total_size {
        let new = min(downloaded + 223211, total_size);
        downloaded = new;
        pb.set_position(new);
        thread::sleep(Duration::from_millis(12));
    }

    pb.finish_with_message("downloaded");
}
<|endoftext|>


<commit_before>extern crate metl;

use metl::extras::window::WindowBuilder;

fn main() {
    let window = WindowBuilder::new().build().unwrap();
    let _device = metl::Device::system_default_device().unwrap();

    for event in window.poll_events() {
        println!("{:?}", event);
    }
}
<commit_msg>Fix event loop of metal_triangle example<commit_after>extern crate metl;

use metl::extras::window::WindowBuilder;
use metl::extras::events::Event;

fn main() {
    let window = WindowBuilder::new().build().unwrap();
    let _device = metl::Device::system_default_device().unwrap();

    'mainloop: loop {
        for event in window.poll_events() {
            match event {
                Event::Closed => {
                    break 'mainloop
                }
                _ => {}
            }
        }

        // drawing code here
    }
}
<|endoftext|>


<commit_before>extern crate iron;

use iron::Handler;
use iron::status;
use iron::IronResult;
use iron::Response;
use iron::Request;
use iron::Iron;

struct MessageHandler {
    message: String
}

impl Handler for MessageHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Ok, self.message.clone())))
    }
}

fn main() {
    let echo = MessageHandler {
        message: "You've found the index page!".to_string()
    };

    let mut router = Router::new();
    router.get("/", echo, "index");

    Iron::new(router).http("localhost:3000").unwrap();
}
<commit_msg>Update struct_handler.rs<commit_after>extern crate iron;
extern crate router;

use iron::Handler;
use iron::status;
use iron::IronResult;
use iron::Response;
use iron::Request;
use iron::Iron;
use router::Router;

struct MessageHandler {
    message: String
}

impl Handler for MessageHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Ok, self.message.clone())))
    }
}

fn main() {
    let handler = MessageHandler {
        message: "You've found the index page!".to_string()
    };

    let mut router = Router::new();
    router.get("/", handler, "index");

    Iron::new(router).http("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;
static mut VISITOR_COUNT: int = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            println(format!("Received request :\n{:s}", request_str));
            let pa = match request_str.find_str("/") {
                Some(x) => x,
                None => -1,
            };
            let th = match request_str.find_str(" HTTP") {
                Some(x) => x,
                None => -1,
            };

            if pa == -1 || th == -1 {
                println!("Error parsing request");
            }
            else if (pa+1) == th {
                unsafe { VISITOR_COUNT += 1 };

                let response: ~str =
                    ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                     <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!
" +
                     format!("
Number of visits: {:d}
", unsafe { VISITOR_COUNT }) +
                     "\r\n";
                stream.write(response.as_bytes());
            }
            else {
                match File::open(&Path::new(request_str.slice(pa+1, th))) {
                    Some(mut file) => {
                        let contents =
                            "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes() +
                            file.read_to_end();
                        stream.write(contents);
                    },
                    None => println!("Error reading file"),
                }
            }

            println!("Connection terminates.");
        }
    }
}

<commit_msg>added error handler for non-.html files<commit_after>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;
static mut VISITOR_COUNT: int = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            println(format!("Received request :\n{:s}", request_str));
            let pa = match request_str.find_str("/") {
                Some(x) => x,
                None => -1,
            };
            let th = match request_str.find_str(" HTTP") {
                Some(x) => x,
                None => -1,
            };

            if pa == -1 || th == -1 {
                println!("Error parsing request");
            }
            else if (pa+1) == th {
                unsafe { VISITOR_COUNT += 1 };

                let response: ~str =
                    ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                     <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!
" +
                     format!("
Number of visits: {:d}
", unsafe { VISITOR_COUNT }) +
                     "\r\n";
                stream.write(response.as_bytes());
            }
            else {
                if request_str.find_str(".html") == None {
                    let forbidden: ~str =
                        ~"HTTP/1.1 418 I'm a teapot\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                         <doctype !html><title>Hello, Rust!</title>

Error 418

                         This server only accepts .html files!
                         \r\n";
                    stream.write(forbidden.as_bytes());
                }
                else {
                    match File::open(&Path::new(request_str.slice(pa+1, th))) {
                        Some(mut file) => {
                            let contents =
                                "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes() +
                                file.read_to_end();
                            stream.write(contents);
                        },
                        None => println!("Error reading file"),
                    }
                }
            }
            println!("Connection terminates.");
        }
    }
}

<|endoftext|>


<commit_before>//! The module containing all incoming packet implementations
//!
//! Any unimplemented packets currently print out the ID and length for future reference (see game_connection.rs)

pub mod handshake;
pub mod status;

/*
//! A packet

use super::super::super::deque_buffer::DequeBuffer;
use super::super::super::game_connection::GameConnection; //It's super super super effective!
use super::super::PacketHeader;

/// A packet sent from the client to
pub struct Packet {

    /// The header of this Packet
    pub header: PacketHeader,

    // Your fields here

}

impl Packet {

    /// Decodes this Packet
    ///
    /// **DO NOT DO ANYTHING EXCEPT DECODING!**
    ///
    /// Actual functionality will be handled in the handle function
    pub fn decode(header: PacketHeader, connection: &mut GameConnection, buffer: &mut DequeBuffer) -> Packet {

        // Decode here

        Packet { header: header /*etc*/ }

    }

    /// Handles this Packet
    pub fn handle(&self, connection: &mut GameConnection) {
        info!("Got a packet!");

        // Ooooh, handle the packet
    }

}
*/
<commit_msg>Remove a doc error<commit_after>//! The module containing all incoming packet implementations
//!
//! Any unimplemented packets currently print out the ID and length for future reference (see game_connection.rs)

pub mod handshake;
pub mod status;

/*
use super::super::super::deque_buffer::DequeBuffer;
use super::super::super::game_connection::GameConnection; //It's super super super effective!
use super::super::PacketHeader;

/// A packet sent from the client to
pub struct Packet {

    /// The header of this Packet
    pub header: PacketHeader,

    // Your fields here

}

impl Packet {

    /// Decodes this Packet
    ///
    /// **DO NOT DO ANYTHING EXCEPT DECODING!**
    ///
    /// Actual functionality will be handled in the handle function
    pub fn decode(header: PacketHeader, connection: &mut GameConnection, buffer: &mut DequeBuffer) -> Packet {

        // Decode here

        Packet { header: header /*etc*/ }

    }

    /// Handles this Packet
    pub fn handle(&self, connection: &mut GameConnection) {
        info!("Got a packet!");

        // Ooooh, handle the packet
    }

}
*/
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fs::OpenOptions;

use crate::Pstore;
use anyhow::{bail, Context, Result};
use base::MemoryMappingBuilder;
use hypervisor::Vm;
use resources::AddressRange;
use vm_memory::GuestAddress;

pub struct RamoopsRegion {
    pub address: u64,
    pub size: u32,
}

/// Creates a mmio memory region for pstore.
pub fn create_memory_region(
    vm: &mut impl Vm,
    region: AddressRange,
    pstore: &Pstore,
) -> Result<RamoopsRegion> {
    let region_size = region.len().context("failed to get region len")?;
    if region_size < pstore.size.into() {
        bail!("insufficient space for pstore {} {}", region, pstore.size);
    }

    let file = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(&pstore.path)
        .context("failed to open pstore")?;
    file.set_len(pstore.size as u64)
        .context("failed to set pstore length")?;

    let memory_mapping = MemoryMappingBuilder::new(pstore.size as usize)
        .from_file(&file)
        .build()
        .context("failed to mmap pstore")?;

    vm.add_memory_region(
        GuestAddress(region.start),
        Box::new(memory_mapping),
        false,
        false,
    )
    .context("failed to add pstore region")?;

    Ok(RamoopsRegion {
        address: region.start,
        size: pstore.size,
    })
}

pub fn add_ramoops_kernel_cmdline(
    cmdline: &mut kernel_cmdline::Cmdline,
    ramoops_region: &RamoopsRegion,
) -> std::result::Result<(), kernel_cmdline::Error> {
    // It seems that default record_size is only 4096 byte even if crosvm allocates
    // more memory. It means that one crash can only 4096 byte.
    // Set record_size and console_size to 1/4 of allocated memory size.
    // This configulation is same as the host.
    let ramoops_opts = [
        ("mem_address", ramoops_region.address),
        ("mem_size", ramoops_region.size as u64),
    ];
    for (name, val) in &ramoops_opts {
        cmdline.insert_str(format!("ramoops.{}={:#x}", name, val))?;
    }
    Ok(())
}
<commit_msg>arch: fix file permissions for Windows pstore.<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fs::OpenOptions;
#[cfg(windows)]
use std::os::windows::fs::OpenOptionsExt;

use crate::Pstore;
use anyhow::{bail, Context, Result};
use base::MemoryMappingBuilder;
use hypervisor::Vm;
use resources::AddressRange;
use vm_memory::GuestAddress;
#[cfg(windows)]
use winapi::um::winnt::FILE_SHARE_READ;

pub struct RamoopsRegion {
    pub address: u64,
    pub size: u32,
}

/// Creates a mmio memory region for pstore.
pub fn create_memory_region(
    vm: &mut impl Vm,
    region: AddressRange,
    pstore: &Pstore,
) -> Result<RamoopsRegion> {
    let region_size = region.len().context("failed to get region len")?;
    if region_size < pstore.size.into() {
        bail!("insufficient space for pstore {} {}", region, pstore.size);
    }

    let mut open_opts = OpenOptions::new();
    open_opts.read(true).write(true).create(true);

    // Allow other applications to read the memory region.
    #[cfg(windows)]
    {
        open_opts.share_mode(FILE_SHARE_READ);
    }

    let file = open_opts
        .open(&pstore.path)
        .context("failed to open pstore")?;
    file.set_len(pstore.size as u64)
        .context("failed to set pstore length")?;

    let memory_mapping = MemoryMappingBuilder::new(pstore.size as usize)
        .from_file(&file)
        .build()
        .context("failed to mmap pstore")?;

    vm.add_memory_region(
        GuestAddress(region.start),
        Box::new(memory_mapping),
        false,
        false,
    )
    .context("failed to add pstore region")?;

    Ok(RamoopsRegion {
        address: region.start,
        size: pstore.size,
    })
}

pub fn add_ramoops_kernel_cmdline(
    cmdline: &mut kernel_cmdline::Cmdline,
    ramoops_region: &RamoopsRegion,
) -> std::result::Result<(), kernel_cmdline::Error> {
    // It seems that default record_size is only 4096 byte even if crosvm allocates
    // more memory. It means that one crash can only 4096 byte.
    // Set record_size and console_size to 1/4 of allocated memory size.
    // This configulation is same as the host.
    let ramoops_opts = [
        ("mem_address", ramoops_region.address),
        ("mem_size", ramoops_region.size as u64),
    ];
    for (name, val) in &ramoops_opts {
        cmdline.insert_str(format!("ramoops.{}={:#x}", name, val))?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            println(format!("Received request :\n{:s}", request_str));

            let response: ~str =
                ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

                 \r\n";
            stream.write(response.as_bytes());
            println!("Connection terminates.");
        }
    }
}
<commit_msg>Commit with zhttpto.rs done through problem 4<commit_after>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;
static mut visitCount: int = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {

        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            //Gets the contents of the 2nd /, so as to check if it is an empty path or not.
            let splitArray: ~[&str] = request_str.split(' ').collect();
            let path = splitArray[1].slice_from(1).to_owned();
            let testVal = ~"/";
            //println!("{}", path);

            println(format!("Received request :\n{:s}", request_str));

            //println!("{}", std::str::eq(&path, &testVal));

            if (std::str::eq(&path, &testVal)) {
                let response: ~str =
                ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

                 \r\n";
                stream.write(response.as_bytes());
            }
            else {
                let filePath = Path::new(path);
                let mut msg_file = File::open(&filePath);
                let msg_bytes: ~[u8] = msg_file.read_to_end();
                stream.write(msg_bytes);
            };
            println!("Connection terminates.");
            unsafe {
                visitCount = visitCount + 1;
                println!("This page has been called {} time(s).", visitCount);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::{cmp, ptr};

#[derive(Debug,PartialEq,Clone)]
pub(crate) struct Buffer {
  memory:   Vec<u8>,
  capacity: usize,
  position: usize,
  end:      usize
}

impl Buffer {
  pub(crate) fn with_capacity(capacity: usize) -> Buffer {
    Buffer {
      memory:   vec![0; capacity],
      capacity,
      position: 0,
      end:      0
    }
  }

  pub(crate) fn grow(&mut self, new_size: usize) -> bool {
    if self.capacity >= new_size {
      return false;
    }

    self.memory.resize(new_size, 0);
    self.capacity = new_size;
    true
  }

  pub(crate) fn available_data(&self) -> usize {
    self.end - self.position
  }

  pub(crate) fn available_space(&self) -> usize {
    self.capacity - self.end
  }

  pub(crate) fn consume(&mut self, count: usize) -> usize {
    let cnt        = cmp::min(count, self.available_data());
    self.position += cnt;
    cnt
  }

  pub(crate) fn fill(&mut self, count: usize) -> usize {
    let cnt   = cmp::min(count, self.available_space());
    self.end += cnt;
    cnt
  }

  pub(crate) fn data(&self) -> &[u8] {
    &self.memory[self.position..self.end]
  }

  pub(crate) fn space(&mut self) -> &mut [u8] {
    &mut self.memory[self.end..self.capacity]
  }

  pub(crate) fn shift(&mut self) {
    let length = self.end - self.position;
    unsafe {
      ptr::copy((&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
    }
    self.position = 0;
    self.end      = length;
  }

  pub(crate) fn shift_unless_available(&mut self, size: usize) {
    if self.available_space() < size {
      self.shift();
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use std::io::Write;

  #[test]
  fn fill_and_consume() {
    let mut b = Buffer::with_capacity(10);
    assert_eq!(b.available_data(), 0);
    assert_eq!(b.available_space(), 10);
    let res = b.space().write(&b"abcd"[..]).map(|size| { b.fill(size); size });
    assert_eq!(res.ok(), Some(4));
    assert_eq!(b.available_data(), 4);
    assert_eq!(b.available_space(), 6);

    assert_eq!(b.data(), &b"abcd"[..]);

    b.consume(2);
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 6);
    assert_eq!(b.data(), &b"cd"[..]);

    b.shift();
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 8);
    assert_eq!(b.data(), &b"cd"[..]);

    assert_eq!(b.space().write(&b"efghijklmnop"[..]).map(|size| { b.fill(size); size }).ok(), Some(8));
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
    b.shift();
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
  }
}
<commit_msg>buffer: impl Write<commit_after>use std::{cmp, io, ptr};

#[derive(Debug,PartialEq,Clone)]
pub(crate) struct Buffer {
  memory:   Vec<u8>,
  capacity: usize,
  position: usize,
  end:      usize
}

impl Buffer {
  pub(crate) fn with_capacity(capacity: usize) -> Buffer {
    Buffer {
      memory:   vec![0; capacity],
      capacity,
      position: 0,
      end:      0
    }
  }

  pub(crate) fn grow(&mut self, new_size: usize) -> bool {
    if self.capacity >= new_size {
      return false;
    }

    self.memory.resize(new_size, 0);
    self.capacity = new_size;
    true
  }

  pub(crate) fn available_data(&self) -> usize {
    self.end - self.position
  }

  pub(crate) fn available_space(&self) -> usize {
    self.capacity - self.end
  }

  pub(crate) fn consume(&mut self, count: usize) -> usize {
    let cnt        = cmp::min(count, self.available_data());
    self.position += cnt;
    cnt
  }

  pub(crate) fn fill(&mut self, count: usize) -> usize {
    let cnt   = cmp::min(count, self.available_space());
    self.end += cnt;
    cnt
  }

  pub(crate) fn data(&self) -> &[u8] {
    &self.memory[self.position..self.end]
  }

  pub(crate) fn space(&mut self) -> &mut [u8] {
    &mut self.memory[self.end..self.capacity]
  }

  pub(crate) fn shift(&mut self) {
    let length = self.end - self.position;
    unsafe {
      ptr::copy((&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
    }
    self.position = 0;
    self.end      = length;
  }

  pub(crate) fn shift_unless_available(&mut self, size: usize) {
    if self.available_space() < size {
      self.shift();
    }
  }
}

impl io::Write for &mut Buffer {
  fn write(&mut self, data: &[u8]) -> io::Result<usize> {
    let amt = self.space().write(data)?;
    self.fill(amt);
    Ok(amt)
  }

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

#[cfg(test)]
mod tests {
  use super::*;
  use std::io::Write;

  #[test]
  fn fill_and_consume() {
    let mut b = Buffer::with_capacity(10);
    assert_eq!(b.available_data(), 0);
    assert_eq!(b.available_space(), 10);
    let res = b.space().write(&b"abcd"[..]).map(|size| { b.fill(size); size });
    assert_eq!(res.ok(), Some(4));
    assert_eq!(b.available_data(), 4);
    assert_eq!(b.available_space(), 6);

    assert_eq!(b.data(), &b"abcd"[..]);

    b.consume(2);
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 6);
    assert_eq!(b.data(), &b"cd"[..]);

    b.shift();
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 8);
    assert_eq!(b.data(), &b"cd"[..]);

    assert_eq!(b.space().write(&b"efghijklmnop"[..]).map(|size| { b.fill(size); size }).ok(), Some(8));
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
    b.shift();
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
  }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::marker::PhantomData;
use std::borrow::{Borrow, BorrowMut};
use gl;
use gl::types::*;
use context::ContextOf;
use framebuffer::FramebufferBinding;
use types::{DrawingMode, GLError};
use index_data::{IndexData, IndexDatum, IndexDatumType};

pub struct Buffer {
    gl_id: GLuint
}

impl Buffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteBuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenBuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Buffer { gl_id: id }
        }
    }
}

impl<BA, BE, F, P, R, T> ContextOf<BufferBinderOf<BA, BE>, F, P, R, T> {
    pub fn bind_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (
            ArrayBufferBinding<'a>,
            ContextOf<BufferBinderOf<(), BE>, F, P, R, T>
        )
        where BA: BorrowMut<ArrayBufferBinder>
    {
        let (mut buffers, gl) = self.split_buffers();
        let (mut ba_binder, buf) = buffers.split_array();
        let gl = gl.join_buffers(buf);
        (ba_binder.borrow_mut().bind(buffer), gl)
    }

    pub fn bind_element_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (
            ElementArrayBufferBinding<'a>,
            ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>
        )
        where BE: BorrowMut<ElementArrayBufferBinder>
    {
        let (mut buffers, gl) = self.split_buffers();
        let (mut be_binder, buf) = buffers.split_element_array();
        let gl = gl.join_buffers(buf);
        (be_binder.borrow_mut().bind(buffer), gl)
    }
}

gl_enum! {
    pub gl_enum BufferDataUsage {
        StreamDraw as STREAM_DRAW = gl::STREAM_DRAW,
        StaticDraw as STATIC_DRAW = gl::STATIC_DRAW,
        DynamicDraw as DYNAMIC_DRAW = gl::DYNAMIC_DRAW
    }
}

gl_enum! {
    pub gl_enum BufferBindingTarget {
        ArrayBuffer as ARRAY_BUFFER = gl::ARRAY_BUFFER,
        ElementArrayBuffer as ELEMENT_ARRAY_BUFFER = gl::ELEMENT_ARRAY_BUFFER
    }
}

pub trait BufferBinding {
    fn target(&self) -> BufferBindingTarget;

    fn buffer_bytes(&mut self, bytes: &[u8], usage: BufferDataUsage) {
        let ptr = bytes.as_ptr();
        let size = bytes.len() * mem::size_of::<u8>();
        unsafe {
            gl::BufferData(self.target().gl_enum(),
                           size as GLsizeiptr,
                           ptr as *const GLvoid,
                           usage.gl_enum());
            dbg_gl_error! {
                GLError::InvalidEnum => "Invalid `target` or `usage`",
                GLError::InvalidValue => "`size` is negative",
                GLError::InvalidOperation => "Object 0 is bound to buffer target",
                GLError::OutOfMemory => "Unable to create a large enough buffer",
                _ => "Unknown error"
            }
        }
    }
}

pub struct ArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ARRAY_BUFFER
    }
}

unsafe fn _draw_elements(mode: DrawingMode,
                         count: usize,
                         index_type: IndexDatumType,
                         indices: *const GLvoid)
{
    let gl_index_type: GLenum = match index_type {
        IndexDatumType::UnsignedByte => gl::UNSIGNED_BYTE,
        IndexDatumType::UnsignedShort => gl::UNSIGNED_SHORT
    };
    gl::DrawElements(mode.gl_enum(),
                     count as GLsizei,
                     gl_index_type,
                     indices);
    dbg_gl_error! {
        GLError::InvalidEnum => "`mode` or `type` is not an accepted value",
        GLError::InvalidValue => "`count` is negative",
        GLError::InvalidFramebufferOperation => "The current framebuffer is not framebuffer-complete",
        _ => "Unknown error"
    }
}

impl<'a> ArrayBufferBinding<'a> {
    pub unsafe fn vertex_attrib_pointer(&self,
                                        attrib: super::ProgramAttrib,
                                        components: i8,
                                        gl_type: super::DataType,
                                        normalized: bool,
                                        stride: usize,
                                        offset: usize)
    {
        debug_assert!(1 <= components && components <= 4);

        let gl_normalized = if normalized { gl::TRUE } else { gl::FALSE };
        gl::VertexAttribPointer(attrib.gl_index,
                                components as GLint,
                                gl_type.gl_enum(),
                                gl_normalized,
                                stride as GLsizei,
                                offset as *const GLvoid);
        dbg_gl_error! {
            GLError::InvalidEnum => "Illegal vertex attribute type",
            GLError::InvalidValue => "`stride` is negative, `size` is not in range, or `index` is >= GL_MAX_VERTEX_ATTRIBS",
            GLError::InvalidFramebufferOperation => "Currently bound framebuffer is not framebuffer complete",
            _ => "Unknown error"
        }
    }
}

impl<'a> FramebufferBinding<'a> {
    pub unsafe fn draw_arrays_range(&mut self,
                                    _ab: &ArrayBufferBinding,
                                    mode: DrawingMode,
                                    first: u32,
                                    count: usize)
    {
        gl::DrawArrays(mode.gl_enum(), first as GLint, count as GLsizei);
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`mode` is not an accepted value",
            GLError::InvalidValue => "`count` is negative",
            _ => "Unknown error"
        }
    }

    pub unsafe fn draw_n_elements_buffered(&mut self,
                                           _ab: &ArrayBufferBinding,
                                           _eab: &ElementArrayBufferBinding,
                                           mode: DrawingMode,
                                           count: usize,
                                           index_type: IndexDatumType)
    {
        _draw_elements(mode, count, index_type, ptr::null());
    }

    pub unsafe fn draw_n_elements<I>(&mut self,
                                     _ab: &ArrayBufferBinding,
                                     mode: DrawingMode,
                                     count: usize,
                                     indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        debug_assert!(count <= indices.len());

        let ptr = indices.index_bytes().as_ptr();
        let index_type = I::index_datum_type();
        _draw_elements(mode, count, index_type, mem::transmute(ptr));
    }

    pub unsafe fn draw_elements<I>(&mut self,
                                   _ab: &ArrayBufferBinding,
                                   mode: DrawingMode,
                                   indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        self.draw_n_elements(_ab, mode, indices.len(), indices);
    }
}

pub struct ElementArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ElementArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ELEMENT_ARRAY_BUFFER
    }
}

fn _bind_buffer(target: BufferBindingTarget, buffer: &mut Buffer) {
    unsafe {
        gl::BindBuffer(target as GLuint, buffer.gl_id());
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`target` is not an allowed value",
            _ => "Unknown error"
        }
    }
}

pub struct BufferBinderOf<A, E> {
    array: A,
    element_array: E
}

pub type BufferBinder = BufferBinderOf<ArrayBufferBinder,
                                       ElementArrayBufferBinder>;

pub type BufferBinderRef<'a> = BufferBinderOf<&'a ArrayBufferBinder,
                                              &'a ElementArrayBufferBinder>;

pub type BufferBinderMut<'a> = BufferBinderOf<&'a mut ArrayBufferBinder,
                                              &'a mut ElementArrayBufferBinder>;

impl<A, E> BufferBinderOf<A, E> {
    pub unsafe fn current() -> BufferBinder {
        BufferBinderOf {
            array: ArrayBufferBinder,
            element_array: ElementArrayBufferBinder
        }
    }

    pub fn borrowed<'a, BA = A, BE = E>(&'a self)
        -> BufferBinderOf<&'a BA, &'a BE>
        where A: Borrow<BA>,
              E: Borrow<BE>
    {
        BufferBinderOf {
            array: self.array.borrow(),
            element_array: self.element_array.borrow()
        }
    }

    pub fn borrowed_mut<'a, BA = A, BE = E>(&'a mut self)
        -> BufferBinderOf<&'a mut BA, &'a mut BE>
        where A: BorrowMut<BA>,
              E: BorrowMut<BE>
    {
        BufferBinderOf {
            array: self.array.borrow_mut(),
            element_array: self.element_array.borrow_mut()
        }
    }

    pub fn split_array(self) -> (A, BufferBinderOf<(), E>) {
        (
            self.array,
            BufferBinderOf {
                array: (),
                element_array: self.element_array
            }
        )
    }

    pub fn split_element_array(self) -> (E, BufferBinderOf<A, ()>) {
        (
            self.element_array,
            BufferBinderOf {
                array: self.array,
                element_array: ()
            }
        )
    }
}

pub struct ArrayBufferBinder;
impl ArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer) -> ArrayBufferBinding<'a>
    {
        let binding = ArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}

pub struct ElementArrayBufferBinder;
impl ElementArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer)
        -> ElementArrayBufferBinding<'a>
    {
        let binding = ElementArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}
<commit_msg>Re-add `Context.split_array_buffer()` and `split_element_array_buffer()`<commit_after>use std::mem;
use std::ptr;
use std::marker::PhantomData;
use std::borrow::{Borrow, BorrowMut};
use gl;
use gl::types::*;
use context::ContextOf;
use framebuffer::FramebufferBinding;
use types::{DrawingMode, GLError};
use index_data::{IndexData, IndexDatum, IndexDatumType};

pub struct Buffer {
    gl_id: GLuint
}

impl Buffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteBuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenBuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Buffer { gl_id: id }
        }
    }
}

impl<BA, BE, F, P, R, T> ContextOf<BufferBinderOf<BA, BE>, F, P, R, T> {
    pub fn split_array_buffer(self)
        -> (BA, ContextOf<BufferBinderOf<(), BE>, F, P, R, T>)
    {
        let (buffers, gl) = self.split_buffers();
        let (ba_binder, rest_buffers) = buffers.split_array();

        (ba_binder, gl.join_buffers(rest_buffers))
    }

    pub fn split_element_array_buffer(self)
        -> (BE, ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>)
    {
        let (buffers, gl) = self.split_buffers();
        let (be_binder, rest_buffers) = buffers.split_element_array();
        (be_binder, gl.join_buffers(rest_buffers))
    }

    pub fn bind_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (
            ArrayBufferBinding<'a>,
            ContextOf<BufferBinderOf<(), BE>, F, P, R, T>
        )
        where BA: BorrowMut<ArrayBufferBinder>
    {
        let (mut ba_binder, gl) = self.split_array_buffer();
        (ba_binder.borrow_mut().bind(buffer), gl)
    }

    pub fn bind_element_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (
            ElementArrayBufferBinding<'a>,
            ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>
        )
        where BE: BorrowMut<ElementArrayBufferBinder>
    {
        let (mut be_binder, gl) = self.split_element_array_buffer();
        (be_binder.borrow_mut().bind(buffer), gl)
    }
}

gl_enum! {
    pub gl_enum BufferDataUsage {
        StreamDraw as STREAM_DRAW = gl::STREAM_DRAW,
        StaticDraw as STATIC_DRAW = gl::STATIC_DRAW,
        DynamicDraw as DYNAMIC_DRAW = gl::DYNAMIC_DRAW
    }
}

gl_enum! {
    pub gl_enum BufferBindingTarget {
        ArrayBuffer as ARRAY_BUFFER = gl::ARRAY_BUFFER,
        ElementArrayBuffer as ELEMENT_ARRAY_BUFFER = gl::ELEMENT_ARRAY_BUFFER
    }
}

pub trait BufferBinding {
    fn target(&self) -> BufferBindingTarget;

    fn buffer_bytes(&mut self, bytes: &[u8], usage: BufferDataUsage) {
        let ptr = bytes.as_ptr();
        let size = bytes.len() * mem::size_of::<u8>();
        unsafe {
            gl::BufferData(self.target().gl_enum(),
                           size as GLsizeiptr,
                           ptr as *const GLvoid,
                           usage.gl_enum());
            dbg_gl_error! {
                GLError::InvalidEnum => "Invalid `target` or `usage`",
                GLError::InvalidValue => "`size` is negative",
                GLError::InvalidOperation => "Object 0 is bound to buffer target",
                GLError::OutOfMemory => "Unable to create a large enough buffer",
                _ => "Unknown error"
            }
        }
    }
}

pub struct ArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ARRAY_BUFFER
    }
}

unsafe fn _draw_elements(mode: DrawingMode,
                         count: usize,
                         index_type: IndexDatumType,
                         indices: *const GLvoid)
{
    let gl_index_type: GLenum = match index_type {
        IndexDatumType::UnsignedByte => gl::UNSIGNED_BYTE,
        IndexDatumType::UnsignedShort => gl::UNSIGNED_SHORT
    };
    gl::DrawElements(mode.gl_enum(),
                     count as GLsizei,
                     gl_index_type,
                     indices);
    dbg_gl_error! {
        GLError::InvalidEnum => "`mode` or `type` is not an accepted value",
        GLError::InvalidValue => "`count` is negative",
        GLError::InvalidFramebufferOperation => "The current framebuffer is not framebuffer-complete",
        _ => "Unknown error"
    }
}

impl<'a> ArrayBufferBinding<'a> {
    pub unsafe fn vertex_attrib_pointer(&self,
                                        attrib: super::ProgramAttrib,
                                        components: i8,
                                        gl_type: super::DataType,
                                        normalized: bool,
                                        stride: usize,
                                        offset: usize)
    {
        debug_assert!(1 <= components && components <= 4);

        let gl_normalized = if normalized { gl::TRUE } else { gl::FALSE };
        gl::VertexAttribPointer(attrib.gl_index,
                                components as GLint,
                                gl_type.gl_enum(),
                                gl_normalized,
                                stride as GLsizei,
                                offset as *const GLvoid);
        dbg_gl_error! {
            GLError::InvalidEnum => "Illegal vertex attribute type",
            GLError::InvalidValue => "`stride` is negative, `size` is not in range, or `index` is >= GL_MAX_VERTEX_ATTRIBS",
            GLError::InvalidFramebufferOperation => "Currently bound framebuffer is not framebuffer complete",
            _ => "Unknown error"
        }
    }
}

impl<'a> FramebufferBinding<'a> {
    pub unsafe fn draw_arrays_range(&mut self,
                                    _ab: &ArrayBufferBinding,
                                    mode: DrawingMode,
                                    first: u32,
                                    count: usize)
    {
        gl::DrawArrays(mode.gl_enum(), first as GLint, count as GLsizei);
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`mode` is not an accepted value",
            GLError::InvalidValue => "`count` is negative",
            _ => "Unknown error"
        }
    }

    pub unsafe fn draw_n_elements_buffered(&mut self,
                                           _ab: &ArrayBufferBinding,
                                           _eab: &ElementArrayBufferBinding,
                                           mode: DrawingMode,
                                           count: usize,
                                           index_type: IndexDatumType)
    {
        _draw_elements(mode, count, index_type, ptr::null());
    }

    pub unsafe fn draw_n_elements<I>(&mut self,
                                     _ab: &ArrayBufferBinding,
                                     mode: DrawingMode,
                                     count: usize,
                                     indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        debug_assert!(count <= indices.len());

        let ptr = indices.index_bytes().as_ptr();
        let index_type = I::index_datum_type();
        _draw_elements(mode, count, index_type, mem::transmute(ptr));
    }

    pub unsafe fn draw_elements<I>(&mut self,
                                   _ab: &ArrayBufferBinding,
                                   mode: DrawingMode,
                                   indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        self.draw_n_elements(_ab, mode, indices.len(), indices);
    }
}

pub struct ElementArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ElementArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ELEMENT_ARRAY_BUFFER
    }
}

fn _bind_buffer(target: BufferBindingTarget, buffer: &mut Buffer) {
    unsafe {
        gl::BindBuffer(target as GLuint, buffer.gl_id());
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`target` is not an allowed value",
            _ => "Unknown error"
        }
    }
}

pub struct BufferBinderOf<A, E> {
    array: A,
    element_array: E
}

pub type BufferBinder = BufferBinderOf<ArrayBufferBinder,
                                       ElementArrayBufferBinder>;

pub type BufferBinderRef<'a> = BufferBinderOf<&'a ArrayBufferBinder,
                                              &'a ElementArrayBufferBinder>;

pub type BufferBinderMut<'a> = BufferBinderOf<&'a mut ArrayBufferBinder,
                                              &'a mut ElementArrayBufferBinder>;

impl<A, E> BufferBinderOf<A, E> {
    pub unsafe fn current() -> BufferBinder {
        BufferBinderOf {
            array: ArrayBufferBinder,
            element_array: ElementArrayBufferBinder
        }
    }

    pub fn borrowed<'a, BA = A, BE = E>(&'a self)
        -> BufferBinderOf<&'a BA, &'a BE>
        where A: Borrow<BA>,
              E: Borrow<BE>
    {
        BufferBinderOf {
            array: self.array.borrow(),
            element_array: self.element_array.borrow()
        }
    }

    pub fn borrowed_mut<'a, BA = A, BE = E>(&'a mut self)
        -> BufferBinderOf<&'a mut BA, &'a mut BE>
        where A: BorrowMut<BA>,
              E: BorrowMut<BE>
    {
        BufferBinderOf {
            array: self.array.borrow_mut(),
            element_array: self.element_array.borrow_mut()
        }
    }

    pub fn split_array(self) -> (A, BufferBinderOf<(), E>) {
        (
            self.array,
            BufferBinderOf {
                array: (),
                element_array: self.element_array
            }
        )
    }

    pub fn split_element_array(self) -> (E, BufferBinderOf<A, ()>) {
        (
            self.element_array,
            BufferBinderOf {
                array: self.array,
                element_array: ()
            }
        )
    }
}

pub struct ArrayBufferBinder;
impl ArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer) -> ArrayBufferBinding<'a>
    {
        let binding = ArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}

pub struct ElementArrayBufferBinder;
impl ElementArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer)
        -> ElementArrayBufferBinding<'a>
    {
        let binding = ElementArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use rustc_serialize::json;

use schema::{UnitOption, UnitStates};
use fleet::FleetAPI;

pub struct Client {
    fleet: FleetAPI,
}

impl Client {
    pub fn new(root_url: &'static str) -> Client {
        Client {
            fleet: FleetAPI::new(root_url)
        }
    }

    pub fn create_unit(
        &self,
        name: &'static str,
        desired_state: UnitStates,
        options: Vec<UnitOption>
    ) -> Result<(), &str> {
        let options_json = json::encode(&options).unwrap();
        let mut body = HashMap::new();

        body.insert("desired_state", desired_state.to_json());
        body.insert("options", &options_json);

        self.fleet.put_units(name, &json::encode(&body).unwrap())
    }
}

#[cfg(test)]
mod client_tests {
    use super::Client;
    use schema::UnitStates;

    #[test]
    fn it_can_be_constructed() {
       Client::new("http://localhost");
    }

    #[test]
    fn it_can_create_units() {
        let client = Client::new("http://it_can_create_units.example.com");

        let result = client.create_unit("example.service", UnitStates::Launched, vec![]);

        assert!(result.is_ok())
    }
}
<commit_msg>Use camel case key for desired state.<commit_after>use std::collections::HashMap;

use rustc_serialize::json;

use schema::{UnitOption, UnitStates};
use fleet::FleetAPI;

pub struct Client {
    fleet: FleetAPI,
}

impl Client {
    pub fn new(root_url: &'static str) -> Client {
        Client {
            fleet: FleetAPI::new(root_url)
        }
    }

    pub fn create_unit(
        &self,
        name: &'static str,
        desired_state: UnitStates,
        options: Vec<UnitOption>
    ) -> Result<(), &str> {
        let options_json = json::encode(&options).unwrap();
        let mut body = HashMap::new();

        body.insert("desiredState", desired_state.to_json());
        body.insert("options", &options_json);

        self.fleet.put_units(name, &json::encode(&body).unwrap())
    }
}

#[cfg(test)]
mod client_tests {
    use super::Client;
    use schema::UnitStates;

    #[test]
    fn it_can_be_constructed() {
       Client::new("http://localhost");
    }

    #[test]
    fn it_can_create_units() {
        let client = Client::new("http://it_can_create_units.example.com");

        let result = client.create_unit("example.service", UnitStates::Launched, vec![]);

        assert!(result.is_ok())
    }
}
<|endoftext|>


<commit_before>//  rpc-perf - RPC Performance Testing
//  Copyright 2015 Twitter, Inc
//
//  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.

extern crate slab;
extern crate mio;
extern crate tic;

use std::collections::VecDeque;
use std::process::exit;
use std::sync::Arc;
use std::time::Duration;

use mio::{Evented, Events, Poll, PollOpt, Ready, Token};
use mio::timer::Timer;
use mio::channel::{Receiver, SyncSender};
use tic::{Clocksource, Sample, Sender};

use cfgtypes::*;
use connection::*;
use stats::Status;

const MAX_CONNECTIONS: usize = 65536;
const MAX_EVENTS: usize = 1024;
const MAX_PENDING: usize = 1024;
const TOKEN_TIMER: Token = Token(MAX_CONNECTIONS + 1);
const TOKEN_QUEUE: Token = Token(MAX_CONNECTIONS + 2);

const TICK_MS: u64 = 1;

fn pollopt_conn() -> PollOpt {
    PollOpt::edge() | PollOpt::oneshot()
}

fn pollopt_timer() -> PollOpt {
    PollOpt::level()
}

fn pollopt_queue() -> PollOpt {
    PollOpt::level()
}

fn ready_timer() -> Ready {
    Ready::readable()
}

fn ready_queue() -> Ready {
    Ready::readable()
}

type Slab<T> = slab::Slab<T, Token>;

pub struct Config {
    servers: Vec<String>,
    pool_size: usize,
    stats: Option<Sender<Status>>,
    clocksource: Option<Clocksource>,
    protocol: Option<Arc<ProtocolParseFactory>>,
    timeout: Option<u64>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            servers: Vec::new(),
            pool_size: 1,
            stats: None,
            clocksource: None,
            protocol: None,
            timeout: None,
        }
    }
}

impl Config {
    /// add an endpoint (host:port)
    pub fn add_server(&mut self, server: String) -> &mut Self {
        self.servers.push(server);
        self.validate()
    }

    /// set the number of connections maintained to each endpoint
    pub fn set_pool_size(&mut self, pool_size: usize) -> &mut Self {
        self.pool_size = pool_size;
        self.validate()
    }

    /// give the client a `Clocksource` for timing
    pub fn set_clocksource(&mut self, clocksource: Clocksource) -> &mut Self {
        self.clocksource = Some(clocksource);
        self
    }

    /// give the client a `ProtocolParseFactory` to read the responses
    pub fn set_protocol(&mut self, protocol: Arc<ProtocolParseFactory>) -> &mut Self {
        self.protocol = Some(protocol);
        self
    }

    /// give the client a `ProtocolParseFactory` to read the responses
    pub fn set_timeout(&mut self, timeout: Option<u64>) -> &mut Self {
        self.timeout = timeout;
        self
    }

    /// turn the `Config` into a `Client`
    pub fn build(mut self) -> Client {
        self.validate();
        Client::configured(self)
    }

    /// sgive the client a stats sender
    pub fn stats(&mut self, stats: Sender<Status>) -> &mut Self {
        self.stats = Some(stats);
        self
    }

    /// validation after set methods
    fn validate(&mut self) -> &mut Self {
        if (self.servers.len() * self.pool_size) > MAX_CONNECTIONS {
            error!("Too many total connections");
            exit(1);
        }
        self
    }
}

pub struct Client {
    connections: Slab<Connection>,
    poll: Poll,
    rx: Receiver<Vec<u8>>,
    tx: SyncSender<Vec<u8>>,
    ready: VecDeque<Token>,
    stats: Sender<Status>,
    times: Vec<u64>,
    clocksource: Clocksource,
    protocol: Box<ProtocolParse>,
    timer: Timer<Token>,
    timeout: Option<u64>,
}

impl Default for Client {
    fn default() -> Client {
        Client::configured(Config::default())
    }
}

impl Client {
    /// returns the default `Config` for a `Client`
    pub fn configure() -> Config {
        Default::default()
    }

    /// turn a `Config` into a `Client`
    fn configured(config: Config) -> Client {
        if config.stats.is_none() {
            error!("need stats");
            exit(1);
        }
        if config.clocksource.is_none() {
            error!("need clocksource");
            exit(1);
        }
        if config.protocol.is_none() {
            error!("need protocol");
            exit(1);
        }

        let (tx, rx) = mio::channel::sync_channel(MAX_PENDING);

        let mut client = Client {
            connections: Slab::with_capacity(MAX_CONNECTIONS),
            poll: Poll::new().unwrap(),
            rx: rx,
            tx: tx,
            ready: VecDeque::new(),
            stats: config.stats.unwrap(),
            times: vec![0; MAX_CONNECTIONS],
            clocksource: config.clocksource.unwrap(),
            protocol: config.protocol.unwrap().clone().new(),
            timer: mio::timer::Builder::default()
                .tick_duration(Duration::from_millis(TICK_MS))
                .build(),
            timeout: config.timeout,
        };

        for server in config.servers {
            for _ in 0..config.pool_size {
                match client.connections.insert(Connection::new(server.clone())) {
                    Ok(token) => {
                        if let Some(s) = client.connections[token].stream() {
                            client.register(s, token, client.connections[token].event_set());
                        } else {
                            error!("failure creating connection");
                        }
                    }
                    Err(_) => {
                        error!("error acquiring token for connection");
                        exit(1);
                    }
                }
            }
        }
        let _ = client.poll.register(&client.timer, TOKEN_TIMER, ready_timer(), pollopt_timer());
        let _ = client.poll.register(&client.rx, TOKEN_QUEUE, ready_queue(), pollopt_queue());

        client
    }

    /// register with the poller
    /// - reregister on failure
    fn register<E: ?Sized>(&self, io: &E, token: Token, interest: Ready)
        where E: Evented
    {
        match self.poll.register(io, token, interest, pollopt_conn()) {
            Ok(_) => {}
            Err(e) => {
                if !self.poll.deregister(io).is_ok() {
                    error!("error registering {:?}: {}", token, e);
                } else {
                    let _ = self.poll
                        .register(io, token, interest, pollopt_conn());
                }
            }
        }
    }

    fn deregister<E: ?Sized>(&self, io: &E)
        where E: Evented
    {
        match self.poll.deregister(io) {
            Ok(_) => {}
            Err(e) => {
                error!("error deregistering: {}", e);
            }
        }
    }

    #[inline]
    fn event_set(&self, token: Token) -> mio::Ready {
        self.connections[token].event_set()
    }

    #[inline]
    fn state(&self, token: Token) -> &State {
        self.connections[token].state()
    }

    #[inline]
    fn set_writable(&mut self, token: Token) {
        self.connections[token].set_writable();
        self.ready.push_back(token);
    }

    /// reconnect helper
    fn reconnect(&mut self, token: Token) {
        debug!("reconnect {:?}", token);
        if let Some(s) = self.connections[token].stream() {
            self.deregister(s);
        }
        self.connections[token].reconnect();
        if let Some(s) = self.connections[token].stream() {
            self.register(s, token, self.event_set(token))
        } else {
            error!("failure reconnecting");
            exit(1);
        }
    }

    /// write bytes to connection
    /// - reconnect on failure
    /// - transition to Reading if entire buffer written in one call
    fn write(&mut self, token: Token, work: Vec<u8>) {
        trace!("send to {:?}", token);
        self.times[token.0] = self.clocksource.counter();
        if self.connections[token].write(work).is_ok() {
            if let Some(t) = self.timeout {
                self.connections[token].set_timeout(self.timer
                    .set_timeout(Duration::from_millis(t), token)
                    .unwrap());
            }
            if let Some(s) = self.connections[token].stream() {
                self.register(s, token, self.event_set(token));
            }
        } else {
            debug!("couldn't write");
            self.reconnect(token);
        }
    }

    /// read and parse response
    /// - reconnect on failure
    /// - transition to Writing when response is complete
    fn read(&mut self, token: Token) {
        if let Ok(response) = self.connections[token].read() {
            if !response.is_empty() {
                let t0 = self.times[token.0];
                let t1 = self.clocksource.counter();

                let parsed = self.protocol.parse(&response);

                let status = match parsed {
                    ParsedResponse::Hit => Status::Hit,
                    ParsedResponse::Ok => Status::Ok,
                    ParsedResponse::Miss => Status::Miss,
                    _ => Status::Error,
                };

                if parsed != ParsedResponse::Incomplete {
                    trace!("switch to writable");
                    let _ = self.stats.send(Sample::new(t0, t1, status));
                    if let Some(timeout) = self.connections[token].get_timeout() {
                        self.timer.cancel_timeout(&timeout);
                    }
                    self.set_writable(token);
                }
            }
        } else {
            debug!("read error. reconnect");
            self.reconnect(token);
        }
    }

    /// timeout handler
    /// - reconnect always
    fn timeout(&mut self, token: Token) {
        debug!("timeout {:?}", token);
        let t0 = self.times[token.0];
        let t1 = self.clocksource.counter();
        let _ = self.stats.send(Sample::new(t0, t1, Status::Timeout));
        self.reconnect(token);
    }

    /// write remaining buffer to underlying stream for token
    /// - reconnect on failure
    /// - transition to Reading when write buffer depleated
    fn flush(&mut self, token: Token) {
        trace!("flush {:?}", token);
        self.times[token.0] = self.clocksource.counter();
        if self.connections[token].flush().is_ok() {
            if let Some(s) = self.connections[token].stream() {
                self.register(s, token, self.event_set(token));
            }
        } else {
            self.reconnect(token);
        }
    }

    /// write a request from the queue to the given token
    fn send(&mut self, token: Token) {
        if self.connections[token].is_writable() {
            let work = self.rx.try_recv().unwrap();
            self.write(token, work);
        } else {
            error!("internal state error. dispatch to non-writable {:?}",
                   self.state(token));
            exit(1);
        }
    }

    /// event handler for connections
    fn connection_ready(&mut self, token: Token, event: mio::Event) {
        if self.connections[token].is_connecting() {
            trace!("connection established {:?}", token);
            self.connections[token].set_writable();
            self.deregister(self.connections[token].stream().unwrap());
            self.ready.push_back(token);
        } else if event.kind().is_readable() {
            trace!("reading event {:?}", token);
            self.read(token);
        } else if event.kind().is_writable() {
            trace!("writing event {:?}", token);
            self.flush(token);
        }
    }

    /// poll for events and handle them
    pub fn poll(&mut self) {
        let mut events = Events::with_capacity(MAX_EVENTS);
        self.poll.poll(&mut events, Some(Duration::from_millis(TICK_MS))).unwrap();

        for event in events.iter() {
            let token = event.token();
            if token.0 <= MAX_CONNECTIONS {
                trace!("connection ready {:?}", token);
                self.connection_ready(token, event);
            } else {
                match token {
                    TOKEN_TIMER => {
                        trace!("timeout fired for {:?}", token);
                        self.timeout(token);
                    }
                    TOKEN_QUEUE => {
                        if !self.ready.is_empty() {
                            // we have work to do and a connection to use
                            let token = self.ready.pop_front().unwrap();
                            self.send(token);
                        }
                    }
                    _ => {
                        error!("unknown token: {:?}", token);
                        exit(1);
                    }
                }
            }
        }
    }

    /// spins on the poll() function to continuously poll for events
    pub fn run(&mut self) {
        loop {
            self.poll();
        }
    }

    /// returns a synchronous sender for pushing requests to the connection
    pub fn tx(&self) -> mio::channel::SyncSender<Vec<u8>> {
        self.tx.clone()
    }
}
<commit_msg>bugfix: timeout token (#119)<commit_after>//  rpc-perf - RPC Performance Testing
//  Copyright 2015 Twitter, Inc
//
//  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.

extern crate slab;
extern crate mio;
extern crate tic;

use std::collections::VecDeque;
use std::process::exit;
use std::sync::Arc;
use std::time::Duration;

use mio::{Evented, Events, Poll, PollOpt, Ready, Token};
use mio::timer::Timer;
use mio::channel::{Receiver, SyncSender};
use tic::{Clocksource, Sample, Sender};

use cfgtypes::*;
use connection::*;
use stats::Status;

const MAX_CONNECTIONS: usize = 65536;
const MAX_EVENTS: usize = 1024;
const MAX_PENDING: usize = 1024;
const TOKEN_TIMER: Token = Token(MAX_CONNECTIONS + 1);
const TOKEN_QUEUE: Token = Token(MAX_CONNECTIONS + 2);

const TICK_MS: u64 = 1;

fn pollopt_conn() -> PollOpt {
    PollOpt::edge() | PollOpt::oneshot()
}

fn pollopt_timer() -> PollOpt {
    PollOpt::level()
}

fn pollopt_queue() -> PollOpt {
    PollOpt::level()
}

fn ready_timer() -> Ready {
    Ready::readable()
}

fn ready_queue() -> Ready {
    Ready::readable()
}

type Slab<T> = slab::Slab<T, Token>;

pub struct Config {
    servers: Vec<String>,
    pool_size: usize,
    stats: Option<Sender<Status>>,
    clocksource: Option<Clocksource>,
    protocol: Option<Arc<ProtocolParseFactory>>,
    timeout: Option<u64>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            servers: Vec::new(),
            pool_size: 1,
            stats: None,
            clocksource: None,
            protocol: None,
            timeout: None,
        }
    }
}

impl Config {
    /// add an endpoint (host:port)
    pub fn add_server(&mut self, server: String) -> &mut Self {
        self.servers.push(server);
        self.validate()
    }

    /// set the number of connections maintained to each endpoint
    pub fn set_pool_size(&mut self, pool_size: usize) -> &mut Self {
        self.pool_size = pool_size;
        self.validate()
    }

    /// give the client a `Clocksource` for timing
    pub fn set_clocksource(&mut self, clocksource: Clocksource) -> &mut Self {
        self.clocksource = Some(clocksource);
        self
    }

    /// give the client a `ProtocolParseFactory` to read the responses
    pub fn set_protocol(&mut self, protocol: Arc<ProtocolParseFactory>) -> &mut Self {
        self.protocol = Some(protocol);
        self
    }

    /// give the client a `ProtocolParseFactory` to read the responses
    pub fn set_timeout(&mut self, timeout: Option<u64>) -> &mut Self {
        self.timeout = timeout;
        self
    }

    /// turn the `Config` into a `Client`
    pub fn build(mut self) -> Client {
        self.validate();
        Client::configured(self)
    }

    /// sgive the client a stats sender
    pub fn stats(&mut self, stats: Sender<Status>) -> &mut Self {
        self.stats = Some(stats);
        self
    }

    /// validation after set methods
    fn validate(&mut self) -> &mut Self {
        if (self.servers.len() * self.pool_size) > MAX_CONNECTIONS {
            error!("Too many total connections");
            exit(1);
        }
        self
    }
}

pub struct Client {
    connections: Slab<Connection>,
    poll: Poll,
    rx: Receiver<Vec<u8>>,
    tx: SyncSender<Vec<u8>>,
    ready: VecDeque<Token>,
    stats: Sender<Status>,
    times: Vec<u64>,
    clocksource: Clocksource,
    protocol: Box<ProtocolParse>,
    timer: Timer<Token>,
    timeout: Option<u64>,
}

impl Default for Client {
    fn default() -> Client {
        Client::configured(Config::default())
    }
}

impl Client {
    /// returns the default `Config` for a `Client`
    pub fn configure() -> Config {
        Default::default()
    }

    /// turn a `Config` into a `Client`
    fn configured(config: Config) -> Client {
        if config.stats.is_none() {
            error!("need stats");
            exit(1);
        }
        if config.clocksource.is_none() {
            error!("need clocksource");
            exit(1);
        }
        if config.protocol.is_none() {
            error!("need protocol");
            exit(1);
        }

        let (tx, rx) = mio::channel::sync_channel(MAX_PENDING);

        let mut client = Client {
            connections: Slab::with_capacity(MAX_CONNECTIONS),
            poll: Poll::new().unwrap(),
            rx: rx,
            tx: tx,
            ready: VecDeque::new(),
            stats: config.stats.unwrap(),
            times: vec![0; MAX_CONNECTIONS],
            clocksource: config.clocksource.unwrap(),
            protocol: config.protocol.unwrap().clone().new(),
            timer: mio::timer::Builder::default()
                .tick_duration(Duration::from_millis(TICK_MS))
                .build(),
            timeout: config.timeout,
        };

        for server in config.servers {
            for _ in 0..config.pool_size {
                match client.connections.insert(Connection::new(server.clone())) {
                    Ok(token) => {
                        if let Some(s) = client.connections[token].stream() {
                            client.register(s, token, client.connections[token].event_set());
                        } else {
                            error!("failure creating connection");
                        }
                    }
                    Err(_) => {
                        error!("error acquiring token for connection");
                        exit(1);
                    }
                }
            }
        }
        let _ = client.poll.register(&client.timer, TOKEN_TIMER, ready_timer(), pollopt_timer());
        let _ = client.poll.register(&client.rx, TOKEN_QUEUE, ready_queue(), pollopt_queue());

        client
    }

    /// register with the poller
    /// - reregister on failure
    fn register<E: ?Sized>(&self, io: &E, token: Token, interest: Ready)
        where E: Evented
    {
        match self.poll.register(io, token, interest, pollopt_conn()) {
            Ok(_) => {}
            Err(e) => {
                if !self.poll.deregister(io).is_ok() {
                    error!("error registering {:?}: {}", token, e);
                } else {
                    let _ = self.poll
                        .register(io, token, interest, pollopt_conn());
                }
            }
        }
    }

    fn deregister<E: ?Sized>(&self, io: &E)
        where E: Evented
    {
        match self.poll.deregister(io) {
            Ok(_) => {}
            Err(e) => {
                error!("error deregistering: {}", e);
            }
        }
    }

    #[inline]
    fn event_set(&self, token: Token) -> mio::Ready {
        self.connections[token].event_set()
    }

    #[inline]
    fn state(&self, token: Token) -> &State {
        self.connections[token].state()
    }

    #[inline]
    fn set_writable(&mut self, token: Token) {
        self.connections[token].set_writable();
        self.ready.push_back(token);
    }

    /// reconnect helper
    fn reconnect(&mut self, token: Token) {
        debug!("reconnect {:?}", token);
        if let Some(s) = self.connections[token].stream() {
            self.deregister(s);
        }
        self.connections[token].reconnect();
        if let Some(s) = self.connections[token].stream() {
            self.register(s, token, self.event_set(token))
        } else {
            error!("failure reconnecting");
            exit(1);
        }
    }

    /// write bytes to connection
    /// - reconnect on failure
    /// - transition to Reading if entire buffer written in one call
    fn write(&mut self, token: Token, work: Vec<u8>) {
        trace!("send to {:?}", token);
        self.times[token.0] = self.clocksource.counter();
        if self.connections[token].write(work).is_ok() {
            if let Some(t) = self.timeout {
                self.connections[token].set_timeout(self.timer
                    .set_timeout(Duration::from_millis(t), token)
                    .unwrap());
            }
            if let Some(s) = self.connections[token].stream() {
                self.register(s, token, self.event_set(token));
            }
        } else {
            debug!("couldn't write");
            self.reconnect(token);
        }
    }

    /// read and parse response
    /// - reconnect on failure
    /// - transition to Writing when response is complete
    fn read(&mut self, token: Token) {
        if let Ok(response) = self.connections[token].read() {
            if !response.is_empty() {
                let t0 = self.times[token.0];
                let t1 = self.clocksource.counter();

                let parsed = self.protocol.parse(&response);

                let status = match parsed {
                    ParsedResponse::Hit => Status::Hit,
                    ParsedResponse::Ok => Status::Ok,
                    ParsedResponse::Miss => Status::Miss,
                    _ => Status::Error,
                };

                if parsed != ParsedResponse::Incomplete {
                    trace!("switch to writable");
                    let _ = self.stats.send(Sample::new(t0, t1, status));
                    if let Some(timeout) = self.connections[token].get_timeout() {
                        self.timer.cancel_timeout(&timeout);
                    }
                    self.set_writable(token);
                }
            }
        } else {
            debug!("read error. reconnect");
            self.reconnect(token);
        }
    }

    /// timeout handler
    /// - reconnect always
    fn timeout(&mut self, token: Token) {
        debug!("timeout {:?}", token);
        let t0 = self.times[token.0];
        let t1 = self.clocksource.counter();
        let _ = self.stats.send(Sample::new(t0, t1, Status::Timeout));
        self.reconnect(token);
    }

    /// write remaining buffer to underlying stream for token
    /// - reconnect on failure
    /// - transition to Reading when write buffer depleated
    fn flush(&mut self, token: Token) {
        trace!("flush {:?}", token);
        self.times[token.0] = self.clocksource.counter();
        if self.connections[token].flush().is_ok() {
            if let Some(s) = self.connections[token].stream() {
                self.register(s, token, self.event_set(token));
            }
        } else {
            self.reconnect(token);
        }
    }

    /// write a request from the queue to the given token
    fn send(&mut self, token: Token) {
        if self.connections[token].is_writable() {
            let work = self.rx.try_recv().unwrap();
            self.write(token, work);
        } else {
            error!("internal state error. dispatch to non-writable {:?}",
                   self.state(token));
            exit(1);
        }
    }

    /// event handler for connections
    fn connection_ready(&mut self, token: Token, event: mio::Event) {
        if self.connections[token].is_connecting() {
            trace!("connection established {:?}", token);
            self.connections[token].set_writable();
            self.deregister(self.connections[token].stream().unwrap());
            self.ready.push_back(token);
        } else if event.kind().is_readable() {
            trace!("reading event {:?}", token);
            self.read(token);
        } else if event.kind().is_writable() {
            trace!("writing event {:?}", token);
            self.flush(token);
        }
    }

    /// poll for events and handle them
    pub fn poll(&mut self) {
        let mut events = Events::with_capacity(MAX_EVENTS);
        self.poll.poll(&mut events, Some(Duration::from_millis(TICK_MS))).unwrap();

        for event in events.iter() {
            let token = event.token();
            if token.0 <= MAX_CONNECTIONS {
                trace!("connection ready {:?}", token);
                self.connection_ready(token, event);
            } else {
                match token {
                    TOKEN_TIMER => {
                        if let Some(token) = self.timer.poll() {
                            trace!("timeout fired for {:?}", token);
                            self.timeout(token);
                        }
                    }
                    TOKEN_QUEUE => {
                        if !self.ready.is_empty() {
                            // we have work to do and a connection to use
                            let token = self.ready.pop_front().unwrap();
                            self.send(token);
                        }
                    }
                    _ => {
                        error!("unknown token: {:?}", token);
                        exit(1);
                    }
                }
            }
        }
    }

    /// spins on the poll() function to continuously poll for events
    pub fn run(&mut self) {
        loop {
            self.poll();
        }
    }

    /// returns a synchronous sender for pushing requests to the connection
    pub fn tx(&self) -> mio::channel::SyncSender<Vec<u8>> {
        self.tx.clone()
    }
}
<|endoftext|>