<commit_before>#![feature(macro_rules)]
extern crate string_telephone;

use string_telephone::{ConnectionConfig, ClientConnectionConfig, Client, Packet, PollEmpty};

use std::io::net::ip::{Ipv4Addr, SocketAddr};
use std::io::net::udp::UdpSocket;
use std::io::Timer;
use std::time::duration::Duration;

fn deserializer(message: &Vec<u8>) -> Option<Vec<u8>> {
    Some(message.clone())
}

fn serializer(packet: &Vec<u8>) -> Vec<u8> {
    packet.clone()
}

fn generate_settings(port: u16, protocol_id: u32) -> (SocketAddr, SocketAddr, ConnectionConfig<Vec<u8>>, ClientConnectionConfig) {
    let my_addr = SocketAddr{ ip: Ipv4Addr(0, 0, 0, 0), port: 0 };
    let target_addr = SocketAddr{ ip: Ipv4Addr(127, 0, 0, 1), port: port };
    let settings = ConnectionConfig::new(protocol_id, 10, deserializer, serializer);
    let client_settings = ClientConnectionConfig::new(1, Duration::seconds(1));
    (my_addr, target_addr, settings, client_settings)
}

fn get_message(socket: &mut UdpSocket) -> (Vec<u8>, SocketAddr) {
    let mut buf = [0, ..255];
    match socket.recv_from(buf) {
        Ok((amt, src)) => (buf.slice_to(amt).to_owned(), src),
        Err(e) => fail!("Socket didn't get a message")
    }
}

macro_rules! with_bound_socket(
    ($socket:ident, ($variable:ident)$code:block) => (
        spawn(proc() {
            match UdpSocket::bind($socket) {
                Ok(mut $variable) => $code,
                Err(e) => fail!(e)
            }
        });
    )
)

/**
 * Test when there isn't a backend to connect to
 * Connect should return an IOResult stating we can't get there
 */
#[test]
fn connection_ignored() {
    let port = 65000;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Reported connected when there is no server!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * Test a normal connection where the backend replies with an accept
 */
#[test]
fn standard_connection() {
    let port = 65001;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(client) => {
            //Success!
        },
        Err(e) => fail!(e)
    };
}

/**
 * If the server gives us back a different protocol id, we shouldn't accept it
 */
#[test]
fn connection_different_protocol_id() {
    let port = 65002;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(122).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Connected to a server with a different protocol ID!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * If the server specifically rejects us, we should give up
 */
#[test]
fn connection_rejected() {
    let port = 65003;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::reject(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Connected to a server that rejected us!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * We should be able to specify how many retries we want
 */
#[test]
fn different_retry_count() {
    let port = 65004;
    let (my_addr, target_addr, settings, mut client_settings) = generate_settings(port, 121);
    client_settings.max_connect_retries = 3;

    let (tx, rx) = channel();
    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let mut attempts = 0u8;
        while attempts < 3 {
            get_message(&mut socket);
            attempts += 1;
        }

        tx.send(attempts);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => (),
        Err(_) => ()
    };

    assert!(rx.recv() == 3);
}

//TODO: Find a sensible way of testing timeout lengths

/**
 * We should instantly return when polling and there's no data available
 */
#[test]
fn empty_polling() {
    let port = 65005;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            assert!(match client.poll() { Err(PollEmpty) => true, _ => false});
        },
        Err(e) => fail!(e)
    };
}

/**
 * We should return an item if there's one there
 */
#[test]
fn single_item_polling() {
    let port = 65006;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![1]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            //May have to wait a bit
            //FIXME: There must be a better way of doing this
            Timer::new().unwrap().sleep(Duration::seconds(1));
            match client.poll() {
                Ok(packet) => {
                    assert!(packet == vec![1]);
                },
                Err(e) => fail!("Couldn't match a polled message! - {}", e)
            };
        },
        Err(e) => fail!(e)
    };
}

/**
 * We should be able to pump multiple items
 */
#[test]
fn multiple_item_polling() {
    let port = 65007;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![1]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![2]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![3]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
    });

    let mut packets: Vec<Vec<u8>> = vec![];

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            //FIXME: There must be a better way of doing this
            Timer::new().unwrap().sleep(Duration::seconds(1));
            loop {
                match client.poll() {
                    Ok(packet) => packets.push(packet),
                    Err(PollEmpty) => break,
                    Err(e) => fail!("Unexpected failure - {}", e)
                };
            }
        },
        Err(e) => fail!("{}", e)
    };

    assert!(packets.len() == 3);
    assert!(packets[0] == vec![1]);
    assert!(packets[1] == vec![2]);
    assert!(packets[2] == vec![3]);
}

/**
 * Messages not intended for us shouldn't be forwarded to us
 */
#[test]
fn ignore_bad_queue_items_polling() {
    let port = 65008;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![1]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(122, vec![2]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![3]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
    });

    let mut packets: Vec<Vec<u8>> = vec![];

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            //FIXME: There must be a better way of doing this
            Timer::new().unwrap().sleep(Duration::seconds(1));
            loop {
                match client.poll() {
                    Ok(packet) => packets.push(packet),
                    Err(PollEmpty) => break,
                    Err(e) => fail!("Unexpected failure - {}", e)
                };
            }
        },
        Err(e) => fail!("{}", e)
    };

    assert!(packets.len() == 2);
    assert!(packets[0] == vec![1]);
    assert!(packets[1] == vec![3]);
}

/**
 * If the other end tells us to hang up, we better listen
 */
#[test]
fn disconnection() {
    let port = 65008;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::disconnect(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
    });

    let mut packets: Vec<Vec<u8>> = vec![];

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            //FIXME: There must be a better way of doing this
            Timer::new().unwrap().sleep(Duration::seconds(1));
            loop {
                match client.poll() {
                    Err(Disconnected) => break,
                    _ => fail!("Unexpected failure")
                };
            }
        },
        Err(e) => fail!("{}", e)
    };
}

/**
 * If the remote end doesn't reply in time, we should time out and disconnect
 */
#[test]
fn timeout() {
    unimplemented!();
}

/**
 * When trying to connect, we should send a connect request message
 */
#[test]
fn send_correct_handshake() {
    unimplemented!();
}

/**
 * We should be able to send data that can be read by the server
 */
#[test]
fn send_data() {
    unimplemented!();
}

/**
 * We should be able to tell the server when we're done
 */
#[test]
fn client_disconnect() {
    unimplemented!();
}
<commit_msg>Timeout testing<commit_after>#![feature(macro_rules)]
extern crate string_telephone;

use string_telephone::{ConnectionConfig, ClientConnectionConfig, Client, Packet, PollEmpty};

use std::io::net::ip::{Ipv4Addr, SocketAddr};
use std::io::net::udp::UdpSocket;
use std::io::Timer;
use std::time::duration::Duration;

fn deserializer(message: &Vec<u8>) -> Option<Vec<u8>> {
    Some(message.clone())
}

fn serializer(packet: &Vec<u8>) -> Vec<u8> {
    packet.clone()
}

fn generate_settings(port: u16, protocol_id: u32) -> (SocketAddr, SocketAddr, ConnectionConfig<Vec<u8>>, ClientConnectionConfig) {
    let my_addr = SocketAddr{ ip: Ipv4Addr(0, 0, 0, 0), port: 0 };
    let target_addr = SocketAddr{ ip: Ipv4Addr(127, 0, 0, 1), port: port };
    let settings = ConnectionConfig::new(protocol_id, 10, deserializer, serializer);
    let client_settings = ClientConnectionConfig::new(1, Duration::seconds(1));
    (my_addr, target_addr, settings, client_settings)
}

fn get_message(socket: &mut UdpSocket) -> (Vec<u8>, SocketAddr) {
    let mut buf = [0, ..255];
    match socket.recv_from(buf) {
        Ok((amt, src)) => (buf.slice_to(amt).to_owned(), src),
        Err(e) => fail!("Socket didn't get a message")
    }
}

macro_rules! with_bound_socket(
    ($socket:ident, ($variable:ident)$code:block) => (
        spawn(proc() {
            match UdpSocket::bind($socket) {
                Ok(mut $variable) => $code,
                Err(e) => fail!(e)
            }
        });
    )
)

/**
 * Test when there isn't a backend to connect to
 * Connect should return an IOResult stating we can't get there
 */
#[test]
fn connection_ignored() {
    let port = 65000;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Reported connected when there is no server!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * Test a normal connection where the backend replies with an accept
 */
#[test]
fn standard_connection() {
    let port = 65001;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(client) => {
            //Success!
        },
        Err(e) => fail!(e)
    };
}

/**
 * If the server gives us back a different protocol id, we shouldn't accept it
 */
#[test]
fn connection_different_protocol_id() {
    let port = 65002;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(122).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Connected to a server with a different protocol ID!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * If the server specifically rejects us, we should give up
 */
#[test]
fn connection_rejected() {
    let port = 65003;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::reject(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => fail!("Connected to a server that rejected us!"),
        Err(e) => {
            assert!(e.desc == "Failed to connect")
        }
    };
}

/**
 * We should be able to specify how many retries we want
 */
#[test]
fn different_retry_count() {
    let port = 65004;
    let (my_addr, target_addr, settings, mut client_settings) = generate_settings(port, 121);
    client_settings.max_connect_retries = 3;

    let (tx, rx) = channel();
    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let mut attempts = 0u8;
        while attempts < 3 {
            get_message(&mut socket);
            attempts += 1;
        }

        tx.send(attempts);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(_) => (),
        Err(_) => ()
    };

    assert!(rx.recv() == 3);
}

//TODO: Find a sensible way of testing timeout lengths

/**
 * We should instantly return when polling and there's no data available
 */
#[test]
fn empty_polling() {
    let port = 65005;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(1000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src);
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            assert!(match client.poll() { Err(PollEmpty) => true, _ => false});
        },
        Err(e) => fail!(e)
    };
}

/**
 * We should return an item if there's one there
 */
#[test]
fn single_item_polling() {
    let port = 65006;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![1]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            //May have to wait a bit
            //FIXME: There must be a better way of doing this
            Timer::new().unwrap().sleep(Duration::seconds(1));
            match client.poll() {
                Ok(packet) => {
                    assert!(packet == vec![1]);
                },
                Err(e) => fail!("Couldn't match a polled message! - {}", e)
            };
        },
        Err(e) => fail!(e)
    };
}

/**
 * We should be able to pump multiple items
 */
#[test]
fn multiple_item_polling() {
    let port = 65007;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![1]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![2]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![3]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
    });

    let mut packets: Vec<Vec<u8>> = vec![];

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            //FIXME: There must be a better way of doing this
            Timer::new().unwrap().sleep(Duration::seconds(1));
            loop {
                match client.poll() {
                    Ok(packet) => packets.push(packet),
                    Err(PollEmpty) => break,
                    Err(e) => fail!("Unexpected failure - {}", e)
                };
            }
        },
        Err(e) => fail!("{}", e)
    };

    assert!(packets.len() == 3);
    assert!(packets[0] == vec![1]);
    assert!(packets[1] == vec![2]);
    assert!(packets[2] == vec![3]);
}

/**
 * Messages not intended for us shouldn't be forwarded to us
 */
#[test]
fn ignore_bad_queue_items_polling() {
    let port = 65008;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![1]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(122, vec![2]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::message(121, vec![3]).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
    });

    let mut packets: Vec<Vec<u8>> = vec![];

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            //FIXME: There must be a better way of doing this
            Timer::new().unwrap().sleep(Duration::seconds(1));
            loop {
                match client.poll() {
                    Ok(packet) => packets.push(packet),
                    Err(PollEmpty) => break,
                    Err(e) => fail!("Unexpected failure - {}", e)
                };
            }
        },
        Err(e) => fail!("{}", e)
    };

    assert!(packets.len() == 2);
    assert!(packets[0] == vec![1]);
    assert!(packets[1] == vec![3]);
}

/**
 * If the other end tells us to hang up, we better listen
 */
#[test]
fn disconnection() {
    let port = 65008;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        socket.send_to(Packet::disconnect(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            //FIXME: There must be a better way of doing this
            Timer::new().unwrap().sleep(Duration::seconds(1));
            loop {
                match client.poll() {
                    Err(Disconnected) => break,
                    _ => fail!("Unexpected failure")
                };
            }
        },
        Err(e) => fail!("{}", e)
    };
}

/**
 * If the remote end doesn't reply in time, we should time out and disconnect
 */
#[test]
fn timeout() {
    let port = 65009;
    let (my_addr, target_addr, settings, client_settings) = generate_settings(port, 121);

    with_bound_socket!(target_addr, (socket) {
        socket.set_timeout(Some(10000));
        let (_, src) = get_message(&mut socket);
        socket.send_to(Packet::accept(121).serialize().unwrap()[], src).ok().expect("Couldn't send a message");
        //Don't send any more data
    });

    match Client::connect(my_addr, target_addr, settings, client_settings) {
        Ok(ref mut client) => {
            //FIXME: There must be a better way of doing this
            Timer::new().unwrap().sleep(Duration::seconds(1));
            loop {
                match client.poll() {
                    Err(Disconnected) => break,
                    _ => fail!("Unexpected failure")
                };
            }
        },
        Err(e) => fail!("{}", e)
    };
}

/**
 * When trying to connect, we should send a connect request message
 */
#[test]
fn send_correct_handshake() {
    unimplemented!();
}

/**
 * We should be able to send data that can be read by the server
 */
#[test]
fn send_data() {
    unimplemented!();
}

/**
 * We should be able to tell the server when we're done
 */
#[test]
fn client_disconnect() {
    unimplemented!();
}
<|endoftext|>


<commit_before>// Copyright 2017-2020 Aron Heinecke
//
// 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.

//! TS data handling functions

use super::*;
use chrono::naive::NaiveDate;

/// Update unknown_ts_ids table based on member clients
/// Handles known member client_id filtering
/// Allows doubled group IDs in member_clients
pub fn update_unknown_ts_ids(conn: &mut PooledConn, member_clients: &[usize]) -> Result<()> {
    create_temp_ts3_table(conn, "t_member_clients")?;
    {
        // insert every member client id into temp table, ignore multi-group clients
        let mut stmt =
            conn.prepare("INSERT IGNORE INTO `t_member_clients` (`client_id`) VALUES (?)")?;
        for client in member_clients {
            stmt.execute((&client,))?;
        }
    }

    {
        // filter everything out that has a member assigned
        conn.prep_exec("DELETE FROM t1 USING `t_member_clients` t1 INNER JOIN `ts_relation` t2 ON ( t1.client_id = t2.client_id )", ())?;
    }

    {
        // truncate unknown ts ids table
        conn.prep_exec("TRUNCATE `unknown_ts_ids`", ())?;
    }

    {
        // replace with correct values
        conn.prep_exec(
            "INSERT INTO `unknown_ts_ids` SELECT * FROM `t_member_clients`",
            (),
        )?;
    }

    Ok(())
}

/// Creates a temporary, single client_id column table with the specified name
fn create_temp_ts3_table(conn: &mut PooledConn, tbl_name: &'static str) -> Result<()> {
    let mut stmt = conn.prepare(format!(
        "CREATE TEMPORARY TABLE `{}` (
                        `client_id` int(11) NOT NULL PRIMARY KEY
                        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
                        ",
        tbl_name
    ))?;
    stmt.execute(())?;
    Ok(())
}

/// Update/Insert ts3 channel names
pub fn upsert_channels(conn: &mut PooledConn, channels: &[Channel]) -> Result<()> {
    let mut stmt = conn.prepare(
        "INSERT INTO `ts_channels` (`channel_id`,`name`) VALUES (?,?) ON DUPLICATE KEY UPDATE `name`=VALUES(`name`)",
    )?;
    for e in channels {
        stmt.execute((e.id, &e.name))?;
    }
    Ok(())
}

pub fn update_ts_names(conn: &mut PooledConn, names: &[TsClient]) -> Result<()> {
    let mut stm_names = conn.prepare(
        "INSERT INTO `ts_names` (`client_id`,`name`) VALUES (?,?) ON DUPLICATE KEY UPDATE `name` = VALUES(`name`)"
    )?;
    for e in names {
        stm_names.execute((e.clid, &e.name))?;
    }
    Ok(())
}

/// Update ts online times & names
pub fn update_ts_activity(
    conn: &mut PooledConn,
    date: &NaiveDate,
    times: &[TsActivity],
) -> Result<()> {
    let mut transaction = conn.start_transaction(false, None, None)?;
    {
        let mut stm_time = transaction.prepare(
        "INSERT INTO `ts_activity` (`date`,`client_id`,`channel_id`,`time`) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE `time` = `time`+VALUES(`time`)",
        )?;

        for e in times {
            stm_time.execute((date, e.client, e.channel, e.time))?;
        }
    }
    transaction.commit()?;
    Ok(())
}

#[cfg(test)]
mod test {
    use super::*;
    use db::testing::*;
    #[test]
    fn test_create_temp_ts3_table() {
        let (mut conn, _guard) = setup_db();
        create_temp_ts3_table(&mut conn, "temp_table").unwrap();
    }

    #[test]
    fn test_update_unknown_ts_ids() {
        let (mut conn, _guard) = setup_db();
        {
            // insert some ids into member ts relation
            let mut stmt = conn
                .prepare("INSERT INTO `ts_relation` (`client_id`,`id`) VALUES (?,1)")
                .unwrap();
            for i in 0..5 {
                stmt.execute((i,)).unwrap();
            }
        }

        {
            // insert some "old" values into the table
            let mut stmt = conn
                .prepare("INSERT INTO `unknown_ts_ids` (`client_id`) VALUES (?)")
                .unwrap();
            for i in 0..10 {
                stmt.execute((i,)).unwrap();
            }
        }

        // include double ids, allows two relevant groups for same client
        update_unknown_ts_ids(&mut conn, &vec![2, 3, 6, 4, 5, 6]).unwrap();

        let res = conn
            .prep_exec(
                "SELECT client_id FROM `unknown_ts_ids` ORDER BY client_id",
                (),
            )
            .unwrap();
        let data: Vec<isize> = res
            .map(|row| {
                let id = from_row(row.unwrap());
                id
            })
            .collect();

        assert_eq!(data, vec![5, 6]);
    }

    fn get_channels_ordered(conn: &mut PooledConn) -> Result<Vec<(ChannelID, String)>> {
        let res = conn.prep_exec(
            "SELECT channel_id,name FROM `ts_channels` ORDER BY channel_id",
            (),
        )?;
        let data: Vec<_> = res
            .map(|row| {
                let row: (ChannelID, String) = from_row(row.unwrap());
                row
            })
            .collect();
        Ok(data)
    }

    #[test]
    fn test_upsert_channels() {
        let (mut conn, _guard) = setup_db();

        let channels = vec![
            Channel {
                id: 2,
                name: "äüö2".to_string(),
            },
            Channel {
                id: 1,
                name: "äöü".to_string(),
            },
        ];

        upsert_channels(&mut conn, &channels).unwrap();

        let data = get_channels_ordered(&mut conn).unwrap();
        assert_eq!(data, vec![(1, "äöü".to_string()), (2, "äüö2".to_string())]);

        // we inserted, let's update one, insert another
        let channels = vec![
            Channel {
                id: 1,
                name: "123".to_string(),
            },
            Channel {
                id: 3,
                name: "345".to_string(),
            },
        ];
        upsert_channels(&mut conn, &channels).unwrap();
        let data = get_channels_ordered(&mut conn).unwrap();
        assert_eq!(
            data,
            vec![
                (1, "123".to_string()),
                (2, "äüö2".to_string()),
                (3, "345".to_string())
            ]
        );
    }

    fn get_ts_activity_ordered(conn: &mut PooledConn) -> Result<Vec<(NaiveDate,TsActivity)>> {
        let res = conn.prep_exec(
            "SELECT client_id,channel_id,time,date FROM `ts_activity` ORDER BY client_id,channel_id",
            (),
        )?;
        let data: Vec<_> = res
            .map(|row| {
                let (client, channel, time,date): (TsClDBID, ChannelID, i32, NaiveDate) = from_row(row.unwrap());
                (date,TsActivity {
                    client,
                    channel,
                    time,
                })
            })
            .collect();
        Ok(data)
    }

    #[test]
    fn test_update_ts_activity() {
        let (mut conn, _guard) = setup_db();

        let data = vec![
            TsActivity {
                client: 1,
                time: 1,
                channel: 1,
            },
            TsActivity {
                client: 1,
                time: 2,
                channel: 2,
            },
            TsActivity {
                client: 2,
                time: 3,
                channel: 1,
            },
        ];
        let date = NaiveDate::from_ymd(2020, 03, 29);
        update_ts_activity(&mut conn, &date, &data).unwrap();

        let res = get_ts_activity_ordered(&mut conn).unwrap();
        for i in 0..res.len() {
            let (r_date,act) = &res[i];
            assert_eq!(*r_date,date);
            assert_eq!(act,&data[i]);
        }

        // now update it
        let data = vec![
            TsActivity {
                client: 1,
                time: 10,
                channel: 1,
            },
            TsActivity {
                client: 2,
                time: 10,
                channel: 1,
            },
        ];
        update_ts_activity(&mut conn, &date, &data).unwrap();
        let res = get_ts_activity_ordered(&mut conn).unwrap();
        let expected: Vec<_> = vec![
            TsActivity {
                client: 1,
                time: 11,
                channel: 1,
            },
            TsActivity {
                client: 1,
                time: 2,
                channel: 2,
            },
            TsActivity {
                client: 2,
                time: 13,
                channel: 1,
            },
        ].drain(..).map(|v|(date.clone(),v)).collect();
        assert_eq!(expected,res);
    }
}
<commit_msg>Add ts name insertion<commit_after>// Copyright 2017-2020 Aron Heinecke
//
// 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.

//! TS data handling functions

use super::*;
use chrono::naive::NaiveDate;

/// Update unknown_ts_ids table based on member clients
/// Handles known member client_id filtering
/// Allows doubled group IDs in member_clients
pub fn update_unknown_ts_ids(conn: &mut PooledConn, member_clients: &[usize]) -> Result<()> {
    create_temp_ts3_table(conn, "t_member_clients")?;
    {
        // insert every member client id into temp table, ignore multi-group clients
        let mut stmt =
            conn.prepare("INSERT IGNORE INTO `t_member_clients` (`client_id`) VALUES (?)")?;
        for client in member_clients {
            stmt.execute((&client,))?;
        }
    }

    {
        // filter everything out that has a member assigned
        conn.prep_exec("DELETE FROM t1 USING `t_member_clients` t1 INNER JOIN `ts_relation` t2 ON ( t1.client_id = t2.client_id )", ())?;
    }

    {
        // truncate unknown ts ids table
        conn.prep_exec("TRUNCATE `unknown_ts_ids`", ())?;
    }

    {
        // replace with correct values
        conn.prep_exec(
            "INSERT INTO `unknown_ts_ids` SELECT * FROM `t_member_clients`",
            (),
        )?;
    }

    Ok(())
}

/// Creates a temporary, single client_id column table with the specified name
fn create_temp_ts3_table(conn: &mut PooledConn, tbl_name: &'static str) -> Result<()> {
    let mut stmt = conn.prepare(format!(
        "CREATE TEMPORARY TABLE `{}` (
                        `client_id` int(11) NOT NULL PRIMARY KEY
                        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
                        ",
        tbl_name
    ))?;
    stmt.execute(())?;
    Ok(())
}

/// Update/Insert ts3 channel names
pub fn upsert_channels(conn: &mut PooledConn, channels: &[Channel]) -> Result<()> {
    let mut stmt = conn.prepare(
        "INSERT INTO `ts_channels` (`channel_id`,`name`) VALUES (?,?) ON DUPLICATE KEY UPDATE `name`=VALUES(`name`)",
    )?;
    for e in channels {
        stmt.execute((e.id, &e.name))?;
    }
    Ok(())
}

pub fn update_ts_names(conn: &mut PooledConn, names: &[TsClient]) -> Result<()> {
    let mut stm_names = conn.prepare(
        "INSERT INTO `ts_names` (`client_id`,`name`) VALUES (?,?) ON DUPLICATE KEY UPDATE `name` = VALUES(`name`)"
    )?;
    for e in names {
        stm_names.execute((e.clid, &e.name))?;
    }
    Ok(())
}

/// Update ts online times & names
pub fn update_ts_activity(
    conn: &mut PooledConn,
    date: &NaiveDate,
    times: &[TsActivity],
) -> Result<()> {
    let mut transaction = conn.start_transaction(false, None, None)?;
    {
        let mut stm_time = transaction.prepare(
        "INSERT INTO `ts_activity` (`date`,`client_id`,`channel_id`,`time`) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE `time` = `time`+VALUES(`time`)",
        )?;

        for e in times {
            stm_time.execute((date, e.client, e.channel, e.time))?;
        }
    }
    transaction.commit()?;
    Ok(())
}

#[cfg(test)]
mod test {
    use super::*;
    use db::testing::*;
    #[test]
    fn test_create_temp_ts3_table() {
        let (mut conn, _guard) = setup_db();
        create_temp_ts3_table(&mut conn, "temp_table").unwrap();
    }

    #[test]
    fn test_update_unknown_ts_ids() {
        let (mut conn, _guard) = setup_db();
        {
            // insert some ids into member ts relation
            let mut stmt = conn
                .prepare("INSERT INTO `ts_relation` (`client_id`,`id`) VALUES (?,1)")
                .unwrap();
            for i in 0..5 {
                stmt.execute((i,)).unwrap();
            }
        }

        {
            // insert some "old" values into the table
            let mut stmt = conn
                .prepare("INSERT INTO `unknown_ts_ids` (`client_id`) VALUES (?)")
                .unwrap();
            for i in 0..10 {
                stmt.execute((i,)).unwrap();
            }
        }

        // include double ids, allows two relevant groups for same client
        update_unknown_ts_ids(&mut conn, &vec![2, 3, 6, 4, 5, 6]).unwrap();

        let res = conn
            .prep_exec(
                "SELECT client_id FROM `unknown_ts_ids` ORDER BY client_id",
                (),
            )
            .unwrap();
        let data: Vec<isize> = res
            .map(|row| {
                let id = from_row(row.unwrap());
                id
            })
            .collect();

        assert_eq!(data, vec![5, 6]);
    }

    fn get_channels_ordered(conn: &mut PooledConn) -> Result<Vec<(ChannelID, String)>> {
        let res = conn.prep_exec(
            "SELECT channel_id,name FROM `ts_channels` ORDER BY channel_id",
            (),
        )?;
        let data: Vec<_> = res
            .map(|row| {
                let row: (ChannelID, String) = from_row(row.unwrap());
                row
            })
            .collect();
        Ok(data)
    }

    #[test]
    fn test_upsert_channels() {
        let (mut conn, _guard) = setup_db();

        let channels = vec![
            Channel {
                id: 2,
                name: "äüö2".to_string(),
            },
            Channel {
                id: 1,
                name: "äöü".to_string(),
            },
        ];

        upsert_channels(&mut conn, &channels).unwrap();

        let data = get_channels_ordered(&mut conn).unwrap();
        assert_eq!(data, vec![(1, "äöü".to_string()), (2, "äüö2".to_string())]);

        // we inserted, let's update one, insert another
        let channels = vec![
            Channel {
                id: 1,
                name: "123".to_string(),
            },
            Channel {
                id: 3,
                name: "345".to_string(),
            },
        ];
        upsert_channels(&mut conn, &channels).unwrap();
        let data = get_channels_ordered(&mut conn).unwrap();
        assert_eq!(
            data,
            vec![
                (1, "123".to_string()),
                (2, "äüö2".to_string()),
                (3, "345".to_string())
            ]
        );
    }

    fn get_ts_activity_ordered(conn: &mut PooledConn) -> Result<Vec<(NaiveDate,TsActivity)>> {
        let res = conn.prep_exec(
            "SELECT client_id,channel_id,time,date FROM `ts_activity` ORDER BY client_id,channel_id",
            (),
        )?;
        let data: Vec<_> = res
            .map(|row| {
                let (client, channel, time,date): (TsClDBID, ChannelID, i32, NaiveDate) = from_row(row.unwrap());
                (date,TsActivity {
                    client,
                    channel,
                    time,
                })
            })
            .collect();
        Ok(data)
    }

    #[test]
    fn test_update_ts_activity() {
        let (mut conn, _guard) = setup_db();

        let data = vec![
            TsActivity {
                client: 1,
                time: 1,
                channel: 1,
            },
            TsActivity {
                client: 1,
                time: 2,
                channel: 2,
            },
            TsActivity {
                client: 2,
                time: 3,
                channel: 1,
            },
        ];
        let date = NaiveDate::from_ymd(2020, 03, 29);
        update_ts_activity(&mut conn, &date, &data).unwrap();

        let res = get_ts_activity_ordered(&mut conn).unwrap();
        for i in 0..res.len() {
            let (r_date,act) = &res[i];
            assert_eq!(*r_date,date);
            assert_eq!(act,&data[i]);
        }

        // now update it
        let data = vec![
            TsActivity {
                client: 1,
                time: 10,
                channel: 1,
            },
            TsActivity {
                client: 2,
                time: 10,
                channel: 1,
            },
        ];
        update_ts_activity(&mut conn, &date, &data).unwrap();
        let res = get_ts_activity_ordered(&mut conn).unwrap();
        let expected: Vec<_> = vec![
            TsActivity {
                client: 1,
                time: 11,
                channel: 1,
            },
            TsActivity {
                client: 1,
                time: 2,
                channel: 2,
            },
            TsActivity {
                client: 2,
                time: 13,
                channel: 1,
            },
        ].drain(..).map(|v|(date.clone(),v)).collect();
        assert_eq!(expected,res);
    }

    fn get_ts_names_ordered(conn: &mut PooledConn) -> Result<Vec<TsClient>> {
        let res = conn.prep_exec(
            "SELECT client_id,name FROM `ts_names` ORDER BY client_id",
            (),
        )?;
        let data: Vec<_> = res
            .map(|row| {
                let (client, name): (TsClDBID, String) = from_row(row.unwrap());
                TsClient {
                    clid: client,
                    name,
                    channel: 0,
                    groups: Vec::new()
                }
            })
            .collect();
        Ok(data)
    }

    #[test]
    fn test_update_ts_names() {
        let (mut conn, _guard) = setup_db();
        let data = vec![
            TsClient {
                channel: 0,
                clid: 1,
                groups: Vec::new(),
                name: "abc".to_string(),
            },
            TsClient {
                channel: 0,
                clid: 2,
                groups: Vec::new(),
                name: "クマ".to_string(),
            },
        ];
        update_ts_names(&mut conn, &data).unwrap();

        let res = get_ts_names_ordered(&mut conn).unwrap();
        assert_eq!(res,data);
        // update
        let data = vec![
            TsClient {
                channel: 0,
                clid: 1,
                groups: Vec::new(),
                name: "def".to_string(),
            },
            TsClient {
                channel: 0,
                clid: 3,
                groups: Vec::new(),
                name: "123".to_string(),
            }
        ];
        update_ts_names(&mut conn, &data).unwrap();
        let res = get_ts_names_ordered(&mut conn).unwrap();
        let expected = vec![
            TsClient {
                channel: 0,
                clid: 1,
                groups: Vec::new(),
                name: "def".to_string(),
            },
            TsClient {
                channel: 0,
                clid: 2,
                groups: Vec::new(),
                name: "クマ".to_string(),
            },
            TsClient {
                channel: 0,
                clid: 3,
                groups: Vec::new(),
                name: "123".to_string(),
            }
        ];
        assert_eq!(res,expected);
    }
}
<|endoftext|>


<commit_before>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io};
use extra::arc;
use extra::time;
use std::comm::*;
use std::hashmap::HashMap;

use std::rt::io::net::tcp::TcpStream;
use std::cmp::Ord;
use std::num::log2;

use extra::priority_queue::*;

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

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    priority: int  // @@@@@@@@@@@@@@@
}

impl std::cmp::Ord for sched_msg
{
	fn lt(&self, other: &sched_msg) -> bool { (*self).priority < (*other).priority }
	fn le(&self, other: &sched_msg) -> bool { (*self).priority <= (*other).priority }
	fn ge(&self, other: &sched_msg) -> bool { (*self).priority >= (*other).priority }
	fn gt(&self, other: &sched_msg) -> bool { (*self).priority > (*other).priority }
}

// determine if the request is from a Charlottesville client

fn is_Wahoo_Client(peer_addr: ~str) ->bool
{
        let WahooIPs: ~[~str] = ~[~"128.143.", ~"137.54."]; // probably add some more ip addresses on the way
        let mut isWahoo = false;
        let mut index = 0;

        while index < WahooIPs.len()
        {
                if peer_addr.starts_with(WahooIPs[index])
                {
                        isWahoo = true;
                        break;
                }
                index += 1;
        }
        //println( fmt!("is wahoo? : %?\n", isWahoo) );
        return isWahoo;
}

// get the size of a file

fn get_fileSize(file_path: &Path) -> int
{
        let mut filestream = std::rt::io::file::open(file_path, Open, Read);
        let mut size:int = 0;

        // find the File size
        match filestream{
                Some(ref mut reader) =>
                {
                        reader.seek(0,SeekEnd);
                        size = reader.tell() as int;
                        reader.seek(0, SeekSet); // rewind the file back

                        println(fmt!("\nfile size: %? bytes \n", size ));
                },
                None => { fail!("\nCannot read the storage file \n");},
        }
        return size;
}

fn main() {

    let visitor_count: uint = 0; // @@@@@@@

/*
    let req_vec: ~[sched_msg] = ~[];
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();
*/

    /* replace data structure to priority queue (this is not the only region changed though) */

    let req_pq: PriorityQueue<sched_msg> = PriorityQueue::new();
    let shared_req_pq = arc::RWArc::new(req_pq);
    let add_pq = shared_req_pq.clone();
    let take_pq = shared_req_pq.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        	let (sm_port, sm_chan) = stream();
        	let (sm_port2, sm_chan2) = stream();

        	// a task for sending responses.
        	do spawn {
         		let mut cache: HashMap<~str, ~[u8]> = std::hashmap::HashMap::new();
         		let mut cacheTimes: HashMap<~str, ~i64> = std::hashmap::HashMap::new();

            		loop {
                		sm_chan2.send(1);
               			let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle

                		let modifiedTime = match file::stat(tf.filepath)
				{
                        		Some(s) => {s.modified}
                        		None 	=> {-1}
				};

                		if cache.contains_key_equiv(&tf.filepath.to_str()) &&
                           		*cacheTimes.get_copy(&tf.filepath.to_str()) as u64 > modifiedTime
				{
					println(fmt!("begin serving file [%?]", tf.filepath));
                        		// A web server should always reply a HTTP header for any legal HTTP request.
                        		tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes());
                        		let data = cache.get_copy(&tf.filepath.to_str());
                        		tf.stream.write(data);
                        		println(fmt!("finish file [%?]", tf.filepath));
                		}
                		else {
                 			let file = io::read_whole_file(tf.filepath);

            	 			match file { // killed if file size is larger than memory size.

                         			Ok(file_data) =>
						{
                          				println(fmt!("begin serving file [%?]", tf.filepath));
                          				// A web server should always reply a HTTP header for any legal HTTP request.
                          				tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes());
                                			tf.stream.write(file_data);
                                			println(fmt!("finish file [%?]", tf.filepath));
                                			cache.insert(tf.filepath.to_str(), file_data);
                                			cacheTimes.insert(tf.filepath.to_str(), ~time::get_time().sec);
                             			}
                             			Err(err) =>
						{	println(err);
						}
                    			}
                		} // else
           		} // loop
        	} // spawn (inner)

        loop {
	    sm_port2.recv();
            port.recv(); // wait for arrving notification
            do take_pq.write |priority_Q| {
                if ((*priority_Q).len() > 0) {
                    // LIFO didn't make sense in service scheduling, so we modify it as FIFO by using shift_opt() rather than pop().

		    //let tf_opt: Option<sched_msg> = (*priority_Q).pop();
                    let tf = (*priority_Q).pop();
                    println(fmt!("shift from queue, size: %ud", (*priority_Q).len()));    // ^^^^^^^^^^^^^^^^^^^ probably need to change it later
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    } // spawn (outer)

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None     => {println(fmt!("Error: Invalid IP address <%s>", IP));
                                                    	return;}
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    let shared_count = arc::RWArc::new( visitor_count ); // @@@@@@

    for stream in acceptor.incoming() {
        let mut stream = stream; // @@@@@@
        let mut peer_addr: ~str = ~"";

        match stream {
                Some(ref mut s) =>
                {
                        match s.peer_name() {
                                Some(pn) =>
                                {   peer_addr = pn.to_str();
                                    println( fmt!("\nPeer address: %s", peer_addr ));
                                },
                                None     => ()
                        }
                }
                None => ()
        }

        let isWahoo: bool = is_Wahoo_Client(peer_addr);
        println( fmt!("is wahoo? : %?\n", isWahoo) );

        let stream = Cell::new(stream);

        let (count_port, count_chan): (Port< extra::arc::RWArc<uint> >, Chan< extra::arc::RWArc<uint> >) = std::comm::stream(); // @@@@@@
        let count_chan = SharedChan::new(count_chan); // @@@@@@
        count_chan.send(shared_count.clone() ); // @@@@@@

        // Start a new task to handle the connection
        let child_chan = chan.clone();
        let child_add_pq = add_pq.clone();

        do spawn {

         let shared_count_copy = count_port.recv(); // @@@@@@

         /* Get Write Access */
         do shared_count_copy.write |count|{
                        *count = *count + 1;
                        println( fmt!("count: %? \n", *count as int) );
         }

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

            let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
            if req_group.len() > 2 {
                let path = req_group[1];
                println(fmt!("Request for path: \n%?", path));

                let file_path = ~os::getcwd().push(path.replace("/../", ""));

                if !os::path_exists(file_path) || os::path_is_dir(file_path)
                {
                    println(fmt!("Request received:\n%s", request_str));

                 	/* Get Read Access */
                	 do shared_count_copy.read |count|
                 	{
                           	let response: ~str = fmt!(
                        	"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!

Visitor count: %u

                        	\r\n", *count);
                        	stream.write(response.as_bytes());
                     	 }

                }
                else {
                    // Requests scheduling

                    let file_size:int = get_fileSize(file_path); // @@@@@@@@@@@

		    // Rust 0.8 only provides a maximum priority queue
		    let mut adjusted_priority: int = (-1) * (log2( file_size as float) as int); // multiply priority by (-1) to use it as minimum priority queue

		    // Implement 'Wahoo-First' scheduling
		    if(isWahoo) { adjusted_priority += 3;}

                    let msg: sched_msg = sched_msg{stream: stream, filepath: file_path.clone(), priority: adjusted_priority };

                    let (sm_port, sm_chan) = std::comm::stream();
                    sm_chan.send(msg);

		    // Implement 'Shortest-Processing-Time-First' scheduling
                    do child_add_pq.write |priority_Q| {
                        let msg = sm_port.recv();
                        (*priority_Q).push(msg); // enqueue new request.
                        println("add to queue");
                    }
                    child_chan.send(""); //notify the new arriving request.

                    println(fmt!("get file request: %?", file_path));
                }
            }
            println!("connection terminates\n")
        }
    }
}

<commit_msg>Improved cache to store limited number of items, when the cache limit is hit the file with the oldest last access time is removed.  Also implemented maximum file size for files in cache.<commit_after>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io};
use extra::arc;
use extra::time;
use std::comm::*;
use std::hashmap::HashMap;

use std::rt::io::net::tcp::TcpStream;
use std::cmp::Ord;
use std::num::log2;

use extra::priority_queue::*;

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

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    priority: int  // @@@@@@@@@@@@@@@
}

impl std::cmp::Ord for sched_msg
{
	fn lt(&self, other: &sched_msg) -> bool { (*self).priority < (*other).priority }
	fn le(&self, other: &sched_msg) -> bool { (*self).priority <= (*other).priority }
	fn ge(&self, other: &sched_msg) -> bool { (*self).priority >= (*other).priority }
	fn gt(&self, other: &sched_msg) -> bool { (*self).priority > (*other).priority }
}

// determine if the request is from a Charlottesville client

fn is_Wahoo_Client(peer_addr: ~str) ->bool
{
        let WahooIPs: ~[~str] = ~[~"128.143.", ~"137.54."]; // probably add some more ip addresses on the way
        let mut isWahoo = false;
        let mut index = 0;

        while index < WahooIPs.len()
        {
                if peer_addr.starts_with(WahooIPs[index])
                {
                        isWahoo = true;
                        break;
                }
                index += 1;
        }
        //println( fmt!("is wahoo? : %?\n", isWahoo) );
        return isWahoo;
}

// get the size of a file

fn get_fileSize(file_path: &Path) -> int
{
        let mut filestream = std::rt::io::file::open(file_path, Open, Read);
        let mut size:int = 0;

        // find the File size
        match filestream{
                Some(ref mut reader) =>
                {
                        reader.seek(0,SeekEnd);
                        size = reader.tell() as int;
                        reader.seek(0, SeekSet); // rewind the file back

                        println(fmt!("\nfile size: %? bytes \n", size ));
                },
                None => { fail!("\nCannot read the storage file \n");},
        }
        return size;
}

fn main() {

    let visitor_count: uint = 0; // @@@@@@@

/*
    let req_vec: ~[sched_msg] = ~[];
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();
*/

    /* replace data structure to priority queue (this is not the only region changed though) */

    let req_pq: PriorityQueue<sched_msg> = PriorityQueue::new();
    let shared_req_pq = arc::RWArc::new(req_pq);
    let add_pq = shared_req_pq.clone();
    let take_pq = shared_req_pq.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        	let (sm_port, sm_chan) = stream();
        	let (sm_port2, sm_chan2) = stream();

        	// a task for sending responses.
        	do spawn {
         		let mut cache: HashMap<~str, ~[u8]> = std::hashmap::HashMap::new();
         		let mut cacheTimes: HashMap<~str, ~i64> = std::hashmap::HashMap::new();
			let mut fileAccessTimes: HashMap<~str, ~i64> = std::hashmap::HashMap::new();
	   		let maxCacheSize = 2;
	    		let maxCacheFileSize = 500000;
            		loop {
                		sm_chan2.send(1);
               			let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle

                		let modifiedTime = match file::stat(tf.filepath)
				{
                        		Some(s) => {s.modified}
                        		None 	=> {-1}
				};

                		if cache.contains_key_equiv(&tf.filepath.to_str()) &&
                           		*cacheTimes.get_copy(&tf.filepath.to_str()) as u64 > modifiedTime
				{
					println(fmt!("begin serving cached file [%?]", tf.filepath));
                        		// A web server should always reply a HTTP header for any legal HTTP request.
                        		tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes());
                        		let data = cache.get_copy(&tf.filepath.to_str());
                        		tf.stream.write(data);
					fileAccessTimes.insert(tf.filepath.to_str(), ~time::get_time().sec);
                        		println(fmt!("finish file [%?]", tf.filepath));
                		}
                		else {
                 			let file = io::read_whole_file(tf.filepath);

            	 			match file { // killed if file size is larger than memory size.

                         			Ok(file_data) =>
						{
                          				println(fmt!("begin serving file [%?]", tf.filepath));
                          				// A web server should always reply a HTTP header for any legal HTTP request.
                          				tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n".as_bytes());
                                			tf.stream.write(file_data);
                                			println(fmt!("finish file [%?]", tf.filepath));
                                			let file_size = get_fileSize(tf.filepath);
							if file_size < maxCacheFileSize {
								cache.insert(tf.filepath.to_str(), file_data);
								cacheTimes.insert(tf.filepath.to_str(), ~time::get_time().sec);
								fileAccessTimes.insert(tf.filepath.to_str(), ~time::get_time().sec);
								if cache.len() > maxCacheSize {
									let clone = fileAccessTimes.clone();
									let mut iterator = clone.iter();

									let mut firstAccessTime: i64;
									let mut firstAccessKey: &~str;
									let mut option = iterator.next();
									match option {
										Some(s) => {
											let (key, value) = s;
											firstAccessTime = **value;
											firstAccessKey = key;
										},
										None => {fail!("hash map iteration failed");}
									}
									let mut i = 0;
									while i < cache.len() - 1 {
										option = iterator.next();
										match option {
											Some(s) => {
												let (key, value) = s;
												if **value < firstAccessTime {
													firstAccessTime = **value;
													firstAccessKey = key;
												}
											},
											None => {fail!("hash map iteration failed");}
										}
										i += 1;
									}
									cache.remove(firstAccessKey);
									cacheTimes.remove(firstAccessKey);
									fileAccessTimes.remove(firstAccessKey);
								}
							}
                             			}
                             			Err(err) =>
						{	println(err);
						}
                    			}
                		} // else
           		} // loop
        	} // spawn (inner)

        loop {
	    sm_port2.recv();
            port.recv(); // wait for arrving notification
            do take_pq.write |priority_Q| {
                if ((*priority_Q).len() > 0) {
                    // LIFO didn't make sense in service scheduling, so we modify it as FIFO by using shift_opt() rather than pop().

		    //let tf_opt: Option<sched_msg> = (*priority_Q).pop();
                    let tf = (*priority_Q).pop();
                    println(fmt!("shift from queue, size: %ud", (*priority_Q).len()));    // ^^^^^^^^^^^^^^^^^^^ probably need to change it later
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    } // spawn (outer)

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None     => {println(fmt!("Error: Invalid IP address <%s>", IP));
                                                    	return;}
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    let shared_count = arc::RWArc::new( visitor_count ); // @@@@@@

    for stream in acceptor.incoming() {
        let mut stream = stream; // @@@@@@
        let mut peer_addr: ~str = ~"";

        match stream {
                Some(ref mut s) =>
                {
                        match s.peer_name() {
                                Some(pn) =>
                                {   peer_addr = pn.to_str();
                                    println( fmt!("\nPeer address: %s", peer_addr ));
                                },
                                None     => ()
                        }
                }
                None => ()
        }

        let isWahoo: bool = is_Wahoo_Client(peer_addr);
        println( fmt!("is wahoo? : %?\n", isWahoo) );

        let stream = Cell::new(stream);

        let (count_port, count_chan): (Port< extra::arc::RWArc<uint> >, Chan< extra::arc::RWArc<uint> >) = std::comm::stream(); // @@@@@@
        let count_chan = SharedChan::new(count_chan); // @@@@@@
        count_chan.send(shared_count.clone() ); // @@@@@@

        // Start a new task to handle the connection
        let child_chan = chan.clone();
        let child_add_pq = add_pq.clone();

        do spawn {

         let shared_count_copy = count_port.recv(); // @@@@@@

         /* Get Write Access */
         do shared_count_copy.write |count|{
                        *count = *count + 1;
                        println( fmt!("count: %? \n", *count as int) );
         }

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

            let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
            if req_group.len() > 2 {
                let path = req_group[1];
                println(fmt!("Request for path: \n%?", path));

                let file_path = ~os::getcwd().push(path.replace("/../", ""));

                if !os::path_exists(file_path) || os::path_is_dir(file_path)
                {
                    println(fmt!("Request received:\n%s", request_str));

                 	/* Get Read Access */
                	 do shared_count_copy.read |count|
                 	{
                           	let response: ~str = fmt!(
                        	"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!

Visitor count: %u

                        	\r\n", *count);
                        	stream.write(response.as_bytes());
                     	 }

                }
                else {
                    // Requests scheduling

                    let file_size:int = get_fileSize(file_path); // @@@@@@@@@@@

		    // Rust 0.8 only provides a maximum priority queue
		    let mut adjusted_priority: int = (-1) * (log2( file_size as float) as int); // multiply priority by (-1) to use it as minimum priority queue

		    // Implement 'Wahoo-First' scheduling
		    if(isWahoo) { adjusted_priority += 3;}

                    let msg: sched_msg = sched_msg{stream: stream, filepath: file_path.clone(), priority: adjusted_priority };

                    let (sm_port, sm_chan) = std::comm::stream();
                    sm_chan.send(msg);

		    // Implement 'Shortest-Processing-Time-First' scheduling
                    do child_add_pq.write |priority_Q| {
                        let msg = sm_port.recv();
                        (*priority_Q).push(msg); // enqueue new request.
                        println("add to queue");
                    }
                    child_chan.send(""); //notify the new arriving request.

                    println(fmt!("get file request: %?", file_path));
                }
            }
            println!("connection terminates\n")
        }
    }
}

<|endoftext|>


<commit_before>//! Private utility module for working with UIDs

use std::borrow::Cow;

pub(crate) fn trim_uid(uid: Cow<str>) -> Cow<str> {
    if uid.ends_with('\0') {
        Cow::Owned(uid.trim_end_matches(|c| c == '\0').to_string())
    } else {
        uid
    }
}

#[cfg(test)]
mod tests {
    use std::borrow::Cow;

    use super::trim_uid;

    #[test]
    fn test_trim_uid() {
        let uid = trim_uid(Cow::from("1.2.3.4"));
        assert_eq!(uid, "1.2.3.4");
        let uid = trim_uid(Cow::from("1.2.3.4\0"));
        assert_eq!(uid, "1.2.3.4");
        let uid = trim_uid(Cow::from("1.2.3.45\0"));
        assert_eq!(uid, "1.2.3.45");
    }
}<commit_msg>[ul] Add robustness to `trim_uid`<commit_after>//! Private utility module for working with UIDs

use std::borrow::Cow;

pub(crate) fn trim_uid(uid: Cow<str>) -> Cow<str> {
    if uid.ends_with('\0') {
        Cow::Owned(uid.trim_end_matches(|c: char| c.is_whitespace() || c == '\0').to_string())
    } else {
        uid
    }
}

#[cfg(test)]
mod tests {
    use std::borrow::Cow;

    use super::trim_uid;

    #[test]
    fn test_trim_uid() {
        let uid = trim_uid(Cow::from("1.2.3.4"));
        assert_eq!(uid, "1.2.3.4");
        let uid = trim_uid(Cow::from("1.2.3.4\0"));
        assert_eq!(uid, "1.2.3.4");
        let uid = trim_uid(Cow::from("1.2.3.45\0"));
        assert_eq!(uid, "1.2.3.45");
    }
}<|endoftext|>


<commit_before>use crate::{Distribution, Float, InverseGaussian, Standard, StandardNormal};
use rand::Rng;

/// Error type returned from `NormalInverseGaussian::new`
#[derive(Debug, PartialEq)]
pub enum Error {
    /// `alpha <= 0` or `nan`.
    AlphaNegativeOrNull,
    /// `|beta| >= alpha` or `nan`.
    AbsoluteBetaLessThanAlpha,
}

/// The [normal-inverse Gaussian distribution](https://en.wikipedia.org/wiki/Normal-inverse_Gaussian_distribution)
#[derive(Debug)]
pub struct NormalInverseGaussian<N> {
    alpha: N,
    beta: N,
    inverse_gaussian: InverseGaussian<N>,
}

impl<N: Float> NormalInverseGaussian<N>
where StandardNormal: Distribution<N>
{
    /// Construct a new `NormalInverseGaussian` distribution with the given alpha (tail heaviness) and
    /// beta (asymmetry) parameters.
    pub fn new(alpha: N, beta: N) -> Result<NormalInverseGaussian<N>, Error> {
        if !(alpha > N::from(0.0)) {
            return Err(Error::AlphaNegativeOrNull);
        }

        if !(beta.abs() < alpha) {
            return Err(Error::AbsoluteBetaLessThanAlpha);
        }

        let gamma = (alpha.powf(N::from(2.)) - beta.powf(N::from(2.))).sqrt();

        let mu = N::from(1.) / gamma;

        let inverse_gaussian = InverseGaussian::new(mu, N::from(1.)).unwrap();

        Ok(Self {
            alpha,
            beta,
            inverse_gaussian,
        })
    }
}

impl<N: Float> Distribution<N> for NormalInverseGaussian<N>
where
    StandardNormal: Distribution<N>,
    Standard: Distribution<N>,
{
    fn sample<R>(&self, rng: &mut R) -> N
    where R: Rng + ?Sized {
        let inv_gauss = rng.sample(&self.inverse_gaussian);

        self.beta * inv_gauss + inv_gauss.sqrt() * rng.sample(StandardNormal)
    }
}

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

    #[test]
    fn test_normal_inverse_gaussian() {
        let norm_inv_gauss = NormalInverseGaussian::new(2.0, 1.0).unwrap();
        let mut rng = crate::test::rng(210);
        for _ in 0..1000 {
            norm_inv_gauss.sample(&mut rng);
        }
    }

    #[test]
    fn test_normal_inverse_gaussian_invalid_param() {
        assert!(NormalInverseGaussian::new(-1.0, 1.0).is_err());
        assert!(NormalInverseGaussian::new(-1.0, -1.0).is_err());
        assert!(NormalInverseGaussian::new(1.0, 2.0).is_err());
        assert!(NormalInverseGaussian::new(2.0, 1.0).is_ok());
    }

    #[test]
    fn value_stability() {
        fn test_samples<N: Float + core::fmt::Debug, D: Distribution<N>>(
            distr: D, zero: N, expected: &[N],
        ) {
            let mut rng = crate::test::rng(213);
            let mut buf = [zero; 4];
            for x in &mut buf {
                *x = rng.sample(&distr);
            }
            assert_eq!(buf, expected);
        }

        test_samples(NormalInverseGaussian::new(2.0, 1.0).unwrap(), 0f32, &[
            0.6568966, 1.3744819, 2.216063, 0.11488572,
        ]);
        test_samples(NormalInverseGaussian::new(2.0, 1.0).unwrap(), 0f64, &[
            0.6838707059642927,
            2.4447306460569784,
            0.2361045023235968,
            1.7774534624785319,
        ]);
    }
}
<commit_msg>Fix error name<commit_after>use crate::{Distribution, Float, InverseGaussian, Standard, StandardNormal};
use rand::Rng;

/// Error type returned from `NormalInverseGaussian::new`
#[derive(Debug, PartialEq)]
pub enum Error {
    /// `alpha <= 0` or `nan`.
    AlphaNegativeOrNull,
    /// `|beta| >= alpha` or `nan`.
    AbsoluteBetaNotLessThanAlpha,
}

/// The [normal-inverse Gaussian distribution](https://en.wikipedia.org/wiki/Normal-inverse_Gaussian_distribution)
#[derive(Debug)]
pub struct NormalInverseGaussian<N> {
    alpha: N,
    beta: N,
    inverse_gaussian: InverseGaussian<N>,
}

impl<N: Float> NormalInverseGaussian<N>
where StandardNormal: Distribution<N>
{
    /// Construct a new `NormalInverseGaussian` distribution with the given alpha (tail heaviness) and
    /// beta (asymmetry) parameters.
    pub fn new(alpha: N, beta: N) -> Result<NormalInverseGaussian<N>, Error> {
        if !(alpha > N::from(0.0)) {
            return Err(Error::AlphaNegativeOrNull);
        }

        if !(beta.abs() < alpha) {
            return Err(Error::AbsoluteBetaLessThanAlpha);
        }

        let gamma = (alpha.powf(N::from(2.)) - beta.powf(N::from(2.))).sqrt();

        let mu = N::from(1.) / gamma;

        let inverse_gaussian = InverseGaussian::new(mu, N::from(1.)).unwrap();

        Ok(Self {
            alpha,
            beta,
            inverse_gaussian,
        })
    }
}

impl<N: Float> Distribution<N> for NormalInverseGaussian<N>
where
    StandardNormal: Distribution<N>,
    Standard: Distribution<N>,
{
    fn sample<R>(&self, rng: &mut R) -> N
    where R: Rng + ?Sized {
        let inv_gauss = rng.sample(&self.inverse_gaussian);

        self.beta * inv_gauss + inv_gauss.sqrt() * rng.sample(StandardNormal)
    }
}

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

    #[test]
    fn test_normal_inverse_gaussian() {
        let norm_inv_gauss = NormalInverseGaussian::new(2.0, 1.0).unwrap();
        let mut rng = crate::test::rng(210);
        for _ in 0..1000 {
            norm_inv_gauss.sample(&mut rng);
        }
    }

    #[test]
    fn test_normal_inverse_gaussian_invalid_param() {
        assert!(NormalInverseGaussian::new(-1.0, 1.0).is_err());
        assert!(NormalInverseGaussian::new(-1.0, -1.0).is_err());
        assert!(NormalInverseGaussian::new(1.0, 2.0).is_err());
        assert!(NormalInverseGaussian::new(2.0, 1.0).is_ok());
    }

    #[test]
    fn value_stability() {
        fn test_samples<N: Float + core::fmt::Debug, D: Distribution<N>>(
            distr: D, zero: N, expected: &[N],
        ) {
            let mut rng = crate::test::rng(213);
            let mut buf = [zero; 4];
            for x in &mut buf {
                *x = rng.sample(&distr);
            }
            assert_eq!(buf, expected);
        }

        test_samples(NormalInverseGaussian::new(2.0, 1.0).unwrap(), 0f32, &[
            0.6568966, 1.3744819, 2.216063, 0.11488572,
        ]);
        test_samples(NormalInverseGaussian::new(2.0, 1.0).unwrap(), 0f64, &[
            0.6838707059642927,
            2.4447306460569784,
            0.2361045023235968,
            1.7774534624785319,
        ]);
    }
}
<|endoftext|>


<commit_before><commit_msg>Added tracking issue to unstable attribute<commit_after><|endoftext|>


<commit_before>use std::rc::Rc;
use std::cell::RefCell;
use std::borrow;
use nalgebra::na;
use ncollide::util::hash_map::HashMap;
use ncollide::util::hash::UintTWHash;
use ncollide::math::N;
use ncollide::broad::{InterferencesBroadPhase};
use ncollide::narrow::{CollisionDetector, GeomGeomCollisionDetector};
use detection::constraint::Constraint;
use object::{RigidBody, Deleted};
use utils::union_find::UFindSet;
use utils::union_find;

pub struct ActivationManager {
    threshold:      N,
    mix_factor:     N,
    ufind:          ~[UFindSet],
    can_deactivate: ~[bool],
    collector:      ~[Constraint],
    to_activate:    ~[Rc<RefCell<RigidBody>>]
}

impl ActivationManager {
    pub fn new(threshold:  N, mix_factor: N) -> ActivationManager {
        assert!(mix_factor >= na::zero() && threshold <= na::one(),
                "The energy mixing factor must be between 0.0 and 1.0.");

        ActivationManager {
            threshold:      threshold,
            mix_factor:     mix_factor,
            ufind:          ~[],
            can_deactivate: ~[],
            collector:      ~[],
            to_activate:    ~[]
        }
    }

    // FIXME: this is not a very good name
    pub fn will_activate(&mut self, b: &Rc<RefCell<RigidBody>>) {
        if b.borrow().with(|b| b.can_move() && !b.is_active()) {
            self.to_activate.push(b.clone());
        }
    }

    fn update_energy(&self, b: &mut RigidBody) {
        // FIXME: take the time in account (to make a true RWA)
        let _1         = na::one::<N>();
        let new_energy = (_1 - self.mix_factor) * b.activation_state().energy() +
            self.mix_factor * (na::sqnorm(&b.lin_vel()) + na::sqnorm(&b.ang_vel()));

        b.activate(new_energy.min(&(self.threshold * na::cast(4.0))));
    }

    pub fn update<BF: InterferencesBroadPhase<Rc<RefCell<RigidBody>>, ~GeomGeomCollisionDetector>>(
                  &mut self,
                  broad_phase: &mut BF,
                  bodies:      &mut HashMap<uint, Rc<RefCell<RigidBody>>, UintTWHash>) {
        /*
         *
         * Update bodies energy
         *
         */
        for (i, b) in bodies.elements().iter().enumerate() {
            b.value.borrow().with_mut(|b| {
                self.update_energy(b);
                b.set_index(i as int);
            });
        }

        /*
         *
         * Build islands to deactivate those with low-energy objects only.
         *
         */
        // resize buffers
        if bodies.len() > self.ufind.len() {
            let to_add = bodies.len() - self.ufind.len();
            self.ufind.grow(to_add, &UFindSet::new(0));
            self.can_deactivate.grow(to_add, &false);
        }
        else {
            self.ufind.truncate(bodies.len());
            self.can_deactivate.truncate(bodies.len());
        }

        // init the union find
        for (i, u) in self.ufind.mut_iter().enumerate() {
            u.reinit(i)
        }

        for d in self.can_deactivate.mut_iter() {
            *d = true
        }

        // run the union-find
        broad_phase.for_each_pair(|b1, b2, cd| {
            let bb1 = b1.borrow().borrow();
            let bb2 = b2.borrow().borrow();

            let rb1 = bb1.get();
            let rb2 = bb2.get();

            if rb1.is_active() && rb2.is_active() && cd.num_colls() != 0 {
                union_find::union(rb1.index() as uint, rb2.index() as uint, self.ufind)
            }
        });

        /*
         *
         * Find deactivable islands and deactivate them
         *
         */
        // find out whether islands can be deactivated
        for i in range(0u, self.ufind.len()) {
            let root = union_find::find(i, self.ufind);
            self.can_deactivate[root] = self.can_deactivate[root] &&
                                        bodies.elements()[i].value.borrow().with(|b| b.activation_state().energy() < self.threshold)

        }

        // deactivate islands having only deactivable objects
        let mut to_deactivate = ~[]; // FIXME: avoid allocation at each update

        for i in range(0u, self.ufind.len()) {
            let root = union_find::find(i, self.ufind);

            if self.can_deactivate[root] { // everybody in this set can be deactivacted
                let b = bodies.elements()[i].value.clone();
                b.borrow().with_mut(|b| b.deactivate());
                to_deactivate.push(b.clone());
            }
        }

        // … so we can really deactivate objects now
        for o in to_deactivate.iter() {
            o.borrow().with_mut(|o| o.deactivate());
            broad_phase.deactivate(o);
            bodies.remove(&borrow::to_uint(o.borrow()));
        }

        /*
         *
         * Activate any deactivated island interfering with an active object.
         *
         */
        while !self.to_activate.is_empty() { // the len will change
            let to_activate = self.to_activate.pop();

            {
                let mut bto_activate = to_activate.borrow().borrow_mut();
                let     b            = bto_activate.get();

                if *b.activation_state() == Deleted {
                    continue
                }
                else {
                    if !b.is_active() {
                        bodies.insert(borrow::to_uint(to_activate.borrow()), to_activate.clone());
                    }

                    b.activate(self.threshold * na::cast(2.0))
                }
            }

            broad_phase.activate(&to_activate, |b1, b2, cd| {
                if cd.num_colls() > 0 {
                    let mut bb1 = b1.borrow().borrow_mut();
                    let mut bb2 = b2.borrow().borrow_mut();

                    let rb1 = bb1.get();
                    let rb2 = bb2.get();

                    if !rb1.is_active() && rb1.can_move() {
                        self.to_activate.push(b1.clone());
                    }

                    if !rb2.is_active() && rb2.can_move() {
                        self.to_activate.push(b2.clone());
                    }
                }
            });
        }
    }
}
<commit_msg>Avoid a systematic allocation of the ActivatonManager.<commit_after>use std::rc::Rc;
use std::cell::RefCell;
use std::borrow;
use nalgebra::na;
use ncollide::util::hash_map::HashMap;
use ncollide::util::hash::UintTWHash;
use ncollide::math::N;
use ncollide::broad::{InterferencesBroadPhase};
use ncollide::narrow::{CollisionDetector, GeomGeomCollisionDetector};
use detection::constraint::Constraint;
use object::{RigidBody, Deleted};
use utils::union_find::UFindSet;
use utils::union_find;

pub struct ActivationManager {
    threshold:      N,
    mix_factor:     N,
    ufind:          ~[UFindSet],
    can_deactivate: ~[bool],
    collector:      ~[Constraint],
    to_activate:    ~[Rc<RefCell<RigidBody>>],
    to_deactivate:  ~[uint]
}

impl ActivationManager {
    pub fn new(threshold:  N, mix_factor: N) -> ActivationManager {
        assert!(mix_factor >= na::zero() && threshold <= na::one(),
                "The energy mixing factor must be between 0.0 and 1.0.");

        ActivationManager {
            threshold:      threshold,
            mix_factor:     mix_factor,
            ufind:          ~[],
            can_deactivate: ~[],
            collector:      ~[],
            to_activate:    ~[],
            to_deactivate:  ~[]
        }
    }

    // FIXME: this is not a very good name
    pub fn will_activate(&mut self, b: &Rc<RefCell<RigidBody>>) {
        if b.borrow().with(|b| b.can_move() && !b.is_active()) {
            self.to_activate.push(b.clone());
        }
    }

    fn update_energy(&self, b: &mut RigidBody) {
        // FIXME: take the time in account (to make a true RWA)
        let _1         = na::one::<N>();
        let new_energy = (_1 - self.mix_factor) * b.activation_state().energy() +
            self.mix_factor * (na::sqnorm(&b.lin_vel()) + na::sqnorm(&b.ang_vel()));

        b.activate(new_energy.min(&(self.threshold * na::cast(4.0))));
    }

    pub fn update<BF: InterferencesBroadPhase<Rc<RefCell<RigidBody>>, ~GeomGeomCollisionDetector>>(
                  &mut self,
                  broad_phase: &mut BF,
                  bodies:      &mut HashMap<uint, Rc<RefCell<RigidBody>>, UintTWHash>) {
        /*
         *
         * Update bodies energy
         *
         */
        for (i, b) in bodies.elements().iter().enumerate() {
            b.value.borrow().with_mut(|b| {
                self.update_energy(b);
                b.set_index(i as int);
            });
        }

        /*
         *
         * Build islands to deactivate those with low-energy objects only.
         *
         */
        // resize buffers
        if bodies.len() > self.ufind.len() {
            let to_add = bodies.len() - self.ufind.len();
            self.ufind.grow(to_add, &UFindSet::new(0));
            self.can_deactivate.grow(to_add, &false);
        }
        else {
            self.ufind.truncate(bodies.len());
            self.can_deactivate.truncate(bodies.len());
        }

        // init the union find
        for (i, u) in self.ufind.mut_iter().enumerate() {
            u.reinit(i)
        }

        for d in self.can_deactivate.mut_iter() {
            *d = true
        }

        // run the union-find
        broad_phase.for_each_pair(|b1, b2, cd| {
            let bb1 = b1.borrow().borrow();
            let bb2 = b2.borrow().borrow();

            let rb1 = bb1.get();
            let rb2 = bb2.get();

            if rb1.is_active() && rb2.is_active() && cd.num_colls() != 0 {
                union_find::union(rb1.index() as uint, rb2.index() as uint, self.ufind)
            }
        });

        /*
         *
         * Find deactivable islands and deactivate them
         *
         */
        // find out whether islands can be deactivated
        for i in range(0u, self.ufind.len()) {
            let root = union_find::find(i, self.ufind);
            self.can_deactivate[root] = self.can_deactivate[root] &&
                                        bodies.elements()[i].value.borrow().with(|b| b.activation_state().energy() < self.threshold)
        }

        // deactivate islands having only deactivable objects
        for i in range(0u, self.ufind.len()) {
            let root = union_find::find(i, self.ufind);

            if self.can_deactivate[root] { // everybody in this set can be deactivacted
                let b = &bodies.elements()[i].value;
                b.borrow().with_mut(|b| b.deactivate());
                broad_phase.deactivate(b);
                self.to_deactivate.push(borrow::to_uint(b.borrow()));
            }
        }

        for b in self.to_deactivate.iter() {
            bodies.remove(b);
        }

        self.to_deactivate.clear();

        /*
         *
         * Activate any deactivated island interfering with an active object.
         *
         */
        while !self.to_activate.is_empty() { // the len will change
            let to_activate = self.to_activate.pop();

            {
                let mut bto_activate = to_activate.borrow().borrow_mut();
                let     b            = bto_activate.get();

                if *b.activation_state() == Deleted {
                    continue
                }
                else {
                    if !b.is_active() {
                        bodies.insert(borrow::to_uint(to_activate.borrow()), to_activate.clone());
                    }

                    b.activate(self.threshold * na::cast(2.0))
                }
            }

            broad_phase.activate(&to_activate, |b1, b2, cd| {
                if cd.num_colls() > 0 {
                    let mut bb1 = b1.borrow().borrow_mut();
                    let mut bb2 = b2.borrow().borrow_mut();

                    let rb1 = bb1.get();
                    let rb2 = bb2.get();

                    if !rb1.is_active() && rb1.can_move() {
                        self.to_activate.push(b1.clone());
                    }

                    if !rb2.is_active() && rb2.can_move() {
                        self.to_activate.push(b2.clone());
                    }
                }
            });
        }
    }
}
<|endoftext|>


<commit_before>extern crate rocks;

use rocks::prelude::*;

pub struct UInt64AddOperator;

fn deserialize(value: &[u8]) -> u64 {
    value
        .iter()
        .enumerate()
        .fold(0, |acc, (i, &v)| acc + ((v as u64) << ((7 - i) * 8)))
}

fn serialize(value: u64) -> Vec<u8> {
    value.to_be_bytes().to_vec()
}

impl AssociativeMergeOperator for UInt64AddOperator {
    fn merge(&self, key: &[u8], existing_value: Option<&[u8]>, value: &[u8], _logger: &Logger) -> Option<Vec<u8>> {
        println!(
            "merge: key = {:?} existing_value = {:?} value = {:?}",
            key, existing_value, value
        );
        // assuming 0 if no existing value
        let existing = existing_value.map(|raw| deserialize(raw)).unwrap_or_default();
        let oper = deserialize(value);

        let new = existing + oper;
        return Some(serialize(new));
    }
}

pub struct MergeBasedCounters {
    db: DB,
}

impl MergeBasedCounters {
    pub fn new(db: DB) -> Self {
        MergeBasedCounters { db }
    }

    pub fn add(&self, key: &str, value: u64) {
        let serialized = serialize(value);
        let _ = self
            .db
            .merge(WriteOptions::default_instance(), key.as_bytes(), &serialized);
    }

    pub fn get(&self, key: &str) -> Option<u64> {
        self.db
            .get(ReadOptions::default_instance(), key.as_bytes())
            .map(|raw| deserialize(&*raw))
            .ok()
    }

    /// mapped to a RocksDB Delete
    pub fn remove(&self, key: &str) {
        self.db
            .delete(WriteOptions::default_instance(), key.as_bytes())
            .unwrap();
    }

    /// mapped to a RocksDB Put
    pub fn set(&self, key: &str, value: u64) {
        let serialized = serialize(value);
        let _ = self
            .db
            .put(WriteOptions::default_instance(), key.as_bytes(), &serialized);
    }
}

fn main() {
    let db = DB::open(
        Options::default()
            .map_db_options(|db| db.create_if_missing(true))
            .map_cf_options(|cf| cf.associative_merge_operator(Box::new(UInt64AddOperator))),
        "./data",
    )
    .unwrap();

    let counters = MergeBasedCounters::new(db);
    // counters.remove("a");
    counters.add("a", 5);
    println!("val => {:?}", counters.get("a"));
    // counters.set("a", 100);
    // println!("val => {:?}", counters.get("a"));
}
<commit_msg>fix(docs): avoid conflicts in example code<commit_after>extern crate rocks;

use rocks::prelude::*;

const DB_PATH: &str = "./data.merge_op";

pub struct UInt64AddOperator;

fn deserialize(value: &[u8]) -> u64 {
    value
        .iter()
        .enumerate()
        .fold(0, |acc, (i, &v)| acc + ((v as u64) << ((7 - i) * 8)))
}

fn serialize(value: u64) -> Vec<u8> {
    value.to_be_bytes().to_vec()
}

impl AssociativeMergeOperator for UInt64AddOperator {
    fn merge(&self, key: &[u8], existing_value: Option<&[u8]>, value: &[u8], _logger: &Logger) -> Option<Vec<u8>> {
        println!(
            "merge: key = {:?} existing_value = {:?} value = {:?}",
            key, existing_value, value
        );
        // assuming 0 if no existing value
        let existing = existing_value.map(|raw| deserialize(raw)).unwrap_or_default();
        let oper = deserialize(value);

        let new = existing + oper;
        return Some(serialize(new));
    }
}

pub struct MergeBasedCounters {
    db: DB,
}

impl MergeBasedCounters {
    pub fn new(db: DB) -> Self {
        MergeBasedCounters { db }
    }

    pub fn add(&self, key: &str, value: u64) {
        let serialized = serialize(value);
        let _ = self
            .db
            .merge(WriteOptions::default_instance(), key.as_bytes(), &serialized);
    }

    pub fn get(&self, key: &str) -> Option<u64> {
        self.db
            .get(ReadOptions::default_instance(), key.as_bytes())
            .map(|raw| deserialize(&*raw))
            .ok()
    }

    /// mapped to a RocksDB Delete
    pub fn remove(&self, key: &str) {
        self.db
            .delete(WriteOptions::default_instance(), key.as_bytes())
            .unwrap();
    }

    /// mapped to a RocksDB Put
    pub fn set(&self, key: &str, value: u64) {
        let serialized = serialize(value);
        let _ = self
            .db
            .put(WriteOptions::default_instance(), key.as_bytes(), &serialized);
    }
}

fn main() {
    let db = DB::open(
        Options::default()
            .map_db_options(|db| db.create_if_missing(true))
            .map_cf_options(|cf| cf.associative_merge_operator(Box::new(UInt64AddOperator))),
        DB_PATH,
    )
    .unwrap();

    let counters = MergeBasedCounters::new(db);
    // counters.remove("a");
    counters.add("a", 5);
    println!("val => {:?}", counters.get("a"));
    // counters.set("a", 100);
    // println!("val => {:?}", counters.get("a"));
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

#[macro_use]
mod commands;

use std::env;

use commands::{streaminfo, comments, seektable, picture};
use docopt::Docopt;

const USAGE: &'static str = "
Usage: metadata <command> [<args>...]
       metadata [options]

Options:
  -h, --help  Show this message.

Commands:
  streaminfo  Display stream information.
  comments    Display or export comment tags.
  seektable   Display seek table.
  picture     Export pictures.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_command: Option<Command>,
  arg_args: Vec<String>,
}

#[derive(Clone, Copy, Debug, RustcDecodable)]
enum Command {
  StreamInfo,
  Comments,
  SeekTable,
  Picture,
}

fn handle_subcommand(command: Command) {
  match command {
    Command::StreamInfo => command!(streaminfo),
    Command::Comments   => command!(comments),
    Command::SeekTable  => command!(seektable),
    Command::Picture    => command!(picture),
  }
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.options_first(true).decode())
    .unwrap_or_else(|e| e.exit());

  if let Some(command) = args.arg_command {
    handle_subcommand(command);
  } else {
    println!("{}", USAGE);
  }
}
<commit_msg>Add flag for listing block names<commit_after>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

#[macro_use]
mod commands;

use std::env;

use commands::{streaminfo, comments, seektable, picture};
use docopt::Docopt;

const USAGE: &'static str = "
Usage: metadata <command> [<args>...]
       metadata [options] [<filename>]

Options:
  --list      List all blocks by name.
  -h, --help  Show this message.

Commands:
  streaminfo  Display stream information.
  comments    Display or export comment tags.
  seektable   Display seek table.
  picture     Export pictures.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_command: Option<Command>,
  arg_filename: Option<String>,
  flag_list: bool,
  arg_args: Vec<String>,
}

#[derive(Clone, Copy, Debug, RustcDecodable)]
enum Command {
  StreamInfo,
  Comments,
  SeekTable,
  Picture,
}

fn handle_subcommand(command: Command) {
  match command {
    Command::StreamInfo => command!(streaminfo),
    Command::Comments   => command!(comments),
    Command::SeekTable  => command!(seektable),
    Command::Picture    => command!(picture),
  }
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.options_first(true).decode())
    .unwrap_or_else(|e| e.exit());

  if let Some(command) = args.arg_command {
    handle_subcommand(command);
  } else {
    println!("{}", USAGE);
  }
}
<|endoftext|>