<commit_before>//! Implements a large hash-table that stores results of previously
//! performed searches ("transposition table").
//!
//! Chess programs, during their brute-force search, encounter the
//! same positions again and again, but from different sequences of
//! moves, which is called a "transposition". When the search
//! encounters a transposition, it is beneficial to "remember" what
//! was determined last time the position was examined, rather than
//! redoing the entire search again. For this reason, chess programs
//! have a transposition table, which is a large hash table storing
//! information about positions previously searched, how deeply they
//! were searched, and what we concluded about them.

use std;
use std::cell::{UnsafeCell, Cell};
use std::mem::transmute;
use std::num::Wrapping;
use basetypes::Value;
use chess_move::MoveDigest;

/// `BOUND_EXACT`, `BOUND_LOWER`, `BOUND_UPPER`, or `BOUND_NONE`.
///
/// For the majority of chess positions our evaluations will be more
/// or less inaccurate, and there is nothing we can do about it. But
/// sometimes we know that a given evaluation is probably inaccurate,
/// and we know the sign of the error. `BoundType` defines the
/// direction of such **known inaccuracies**.
///
/// * `BOUND_EXACT` means that the evaluation is exact (as far as we know).
///
/// * `BOUND_LOWER` means that the real value is greater or equal to
///    the evaluation (as far as we know).
///
/// * `BOUND_UPPER` means that the real value is lesser or equal to
///   the evaluation (as far as we know).
///
/// * `BOUND_NONE` means that the real value might be lesser, equal,
///   or grater than the evaluation.
pub type BoundType = u8;

/// Neither exact value nor a bound.
pub const BOUND_NONE: BoundType = 0;

/// Upper bound.
pub const BOUND_UPPER: BoundType = 0b10;

/// Lower bound.
pub const BOUND_LOWER: BoundType = 0b01;

/// Exact value.
pub const BOUND_EXACT: BoundType = BOUND_UPPER | BOUND_LOWER;

/// Contains information about a particular position.
#[derive(Copy, Clone)]
pub struct TtEntry {
    move16: MoveDigest,
    value: Value,
    eval_value: Value,
    gen_bound: u8,
    depth: u8,
}

impl TtEntry {
    /// Creates a new instance.
    ///
    /// * `value` -- the value assigned to the position;
    ///
    /// * `bound` -- the accuracy of the assigned `value`;
    ///
    /// * `depth` -- the depth of search;
    ///
    /// * `move16` -- best or refutation move, or `0` if no move is
    ///   available;
    ///
    /// * `eval_value` -- the calculated static evaluation for the
    ///   position.
    pub fn new(value: Value,
               bound: BoundType,
               depth: u8,
               move16: MoveDigest,
               eval_value: Value)
               -> TtEntry {
        assert!(bound <= 0b11);
        assert!(depth < 127);
        TtEntry {
            move16: move16,
            value: value,
            eval_value: eval_value,
            gen_bound: bound, // Stores the entry's generation and the bound.
            depth: depth,
        }
    }

    #[inline(always)]
    pub fn value(&self) -> Value {
        self.value
    }

    #[inline(always)]
    pub fn bound(&self) -> BoundType {
        self.gen_bound & 0b11
    }

    #[inline(always)]
    pub fn depth(&self) -> u8 {
        self.depth
    }

    #[inline(always)]
    pub fn move16(&self) -> MoveDigest {
        self.move16
    }

    #[inline(always)]
    pub fn eval_value(&self) -> Value {
        self.eval_value
    }
}

/// Represents a record in the transposition table.
///
/// It consists of 16 bytes, and is laid out the following way:
///
/// * key        64 bit
/// * move16     16 bit
/// * value      16 bit
/// * eval value 16 bit
/// * generation  6 bit
/// * bound type  2 bit
/// * depth       8 bit
#[derive(Copy, Clone)]
struct Record {
    key: u64,
    data: TtEntry,
}

impl Default for Record {
    fn default() -> Record {
        Record {
            key: 0,
            data: unsafe { transmute(0u64) },
        }
    }
}

impl Record {
    /// Returns the contained data as one `u64` value.
    #[inline(always)]
    fn data_u64(&self) -> u64 {
        unsafe { transmute(self.data) }
    }

    /// Returns record's generation.
    #[inline(always)]
    fn generation(&self) -> u8 {
        self.data.gen_bound & 0b11111100
    }

    /// Updates record's generation.
    #[inline(always)]
    fn update_generation(&mut self, generation: u8) {
        assert_eq!(generation & 0b11, 0);

        // Since the `key` is saved XOR-ed with the data, when we
        // change the data, we have to change the stored `key` as
        // well.
        let old_data_u64 = self.data_u64();
        self.data.gen_bound = generation | self.data.bound();
        self.key ^= old_data_u64 ^ self.data_u64();
    }
}

/// A transposition table.
pub struct Tt {
    generation: Cell<u8>,
    cluster_count: usize,
    table: UnsafeCell<Vec<[Record; 4]>>,
}

impl Tt {
    /// Creates a new transposition table.
    ///
    /// The newly created table has the minimum possible size. Before
    /// using the new table for anything, `resize()` should be called
    /// on it, specifying the desired size.
    pub fn new() -> Tt {
        Tt {
            generation: Cell::new(0),
            cluster_count: 1,
            table: UnsafeCell::new(vec![Default::default()]),
        }
    }

    /// Resizes the transpositon table. All entries in the table will
    /// be lost.
    ///
    /// `size_mb` is the desired new size in Mbytes. If `size_mb` is
    /// not in the form "2**n", the new size of the transposition
    /// table will be as close as possible, but less than `size_mb`.
    pub fn resize(&mut self, size_mb: usize) {
        let requested_cluster_count = (size_mb * 1024 * 1024) / std::mem::size_of::<[Record; 4]>();

        // First, make sure `requested_cluster_count` is exceeded.
        let mut new_cluster_count = 1;
        while requested_cluster_count >= new_cluster_count {
            new_cluster_count <<= 1;
        }

        // Then make one step back, being careful so that the new
        // cluster count is not zero.
        if new_cluster_count > 1 {
            new_cluster_count >>= 1;
        } else {
            new_cluster_count = 1;
        }

        // Finally, reallocate the vector of clusters.
        if new_cluster_count != self.cluster_count {
            self.cluster_count = new_cluster_count;
            self.table = UnsafeCell::new(vec![Default::default(); new_cluster_count]);
        }
    }

    /// Returns the size of the transposition table in Mbytes.
    pub fn size(&self) -> usize {
        unsafe { &*self.table.get() }.len() * std::mem::size_of::<[Record; 4]>() / 1024 / 1024
    }

    /// Removes all entries in the table.
    pub fn clear(&self) {
        let table = unsafe { self.table.get().as_mut().unwrap() };
        for cluster in table {
            for record in cluster.iter_mut() {
                *record = Default::default();
            }
        }
        self.generation.set(0);
    }

    /// Signals that a new search is about to begin.
    ///
    /// Internally, the transposition table maintains a generation
    /// counter that is used to implement an efficient replacement
    /// strategy. This method increases this counter.
    pub fn new_search(&self) {
        // Note: The lowest 2 bits of the `generation` field are used
        // for the bound type.
        self.generation.set((Wrapping(self.generation.get()) + Wrapping(0b100)).0);
        assert_eq!(self.generation.get() & 0b11, 0);
    }

    /// Probes for data by a specific key.
    #[inline]
    pub fn probe(&self, key: u64) -> Option<TtEntry> {
        let cluster = unsafe { self.cluster_mut(key) };
        for record in cluster.iter_mut() {
            if record.key ^ record.data_u64() == key {
                // If `key` and `data` were written simultaneously by
                // different search instances with different keys,
                // this will yield in a mismatch of the above
                // comparison (except for the rare and inherent key
                // collisions).
                record.update_generation(self.generation.get());
                return Some(record.data);
            }
        }
        None
    }

    /// Peeks for data by a specific key.
    ///
    /// This method does the same as `probe`, except it does not
    /// update the generation of the entry. This is useful when we
    /// want to extract the primary variation from the the
    /// transposition table, without affecting the entries in the
    /// table.
    #[inline]
    pub fn peek(&self, key: u64) -> Option<TtEntry> {
        let cluster = unsafe { self.cluster_mut(key) };
        for record in cluster.iter_mut() {
            if record.key ^ record.data_u64() == key {
                return Some(record.data);
            }
        }
        None
    }

    /// Stores data by a specific key.
    ///
    /// After being stored, the data might be retrieved by
    /// `probe(key)`. This is not guaranteed though, because in the
    /// meantime it might have been overwritten.
    pub fn store(&self, key: u64, mut data: TtEntry) {
        // `store` and `probe` jointly implement a clever lock-less
        // hashing method. Rather than storing two disjoint items, the
        // key is stored XOR-ed with data, while data is stored
        // additionally as usual.

        // Set the entry's generation.
        data.gen_bound |= self.generation.get();

        // Choose a slot to which to write the data. (Each cluster has
        // 4 slots.)
        let mut cluster = unsafe { self.cluster_mut(key) };
        let mut replace_index = 0;
        let mut replace_score = 0xff;
        for (i, record) in cluster.iter_mut().enumerate() {
            // Check if this is an empty slot, or an old record for
            // the same key. If this this is the case we will use this
            // slot for the new record.
            if record.key == 0 || record.key ^ record.data_u64() == key {
                if data.move16 == 0 {
                    data.move16 = record.data.move16; // Preserve any existing move.
                }
                replace_index = i;
                break;
            }

            // Calculate the score for this record. If we can not find
            // an empty/old slot, the replaced record will be the
            // record with the lowest score.
            let record_score = self.calc_score(record);
            if record_score < replace_score {
                replace_index = i;
                replace_score = record_score;
            }
        }

        // Write the data to the chosen slot.
        unsafe {
            cluster.get_unchecked_mut(replace_index).key = key ^ transmute::<TtEntry, u64>(data);
            cluster.get_unchecked_mut(replace_index).data = data;
        }
    }

    // A helper method for `store`. It implements our replacement
    // strategy. It returns higher values for the records that are
    // move likely to save CPU work in the future.
    #[inline(always)]
    fn calc_score(&self, record: &Record) -> u8 {
        // Positions from the current generation are always scored
        // higher than positions from older generations.
        (if record.generation() == self.generation.get() {
            128
        } else {
            0
        })

        // Positions with higher search depth are scored higher.
        + record.data.depth()

        // Positions with exact evaluation are given slight advantage.
        + (if record.data.bound() == BOUND_EXACT {
            1
        } else {
            0
        })
    }

    // A helper method for `probe` and `store`. It gives the cluster
    // for a given key. (Each cluster can store up to 4 records.)
    #[inline]
    unsafe fn cluster_mut(&self, key: u64) -> &mut [Record; 4] {
        let cluster_index = (key & (self.cluster_count - 1) as u64) as usize;
        self.table.get().as_mut().unwrap().get_unchecked_mut(cluster_index)
    }
}

unsafe impl Sync for Tt {}

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

    #[test]
    fn test_cluster_size() {
        assert_eq!(std::mem::size_of::<[Record; 4]>(), 64);
        assert_eq!(std::mem::size_of::<Record>(), 16);
    }

    #[test]
    fn test_tt_resize() {
        let mut tt = Tt::new();
        assert_eq!(unsafe { &*tt.table.get() }.capacity(), 1);
        tt.resize(1);
        assert_eq!(tt.size(), 1);
        tt.clear();
    }

    #[test]
    fn test_store_and_probe() {
        let tt = Tt::new();
        assert!(tt.probe(1).is_none());
        let data = TtEntry::new(0, 0, 100, 666, 0);
        assert_eq!(data.depth(), 100);
        assert_eq!(data.move16(), 666);
        tt.store(1, data);
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        tt.store(1, TtEntry::new(0, 0, 100, 666, 0));
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        assert_eq!(tt.probe(1).unwrap().move16(), 666);
        for i in 2..100 {
            tt.store(i, TtEntry::new(i as i16, 0, i as u8, i as u16, i as i16));
        }
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        assert_eq!(tt.probe(99).unwrap().depth(), 99);
        assert_eq!(tt.probe(98).unwrap().depth(), 98);
        assert_eq!(tt.probe(97).unwrap().depth(), 97);
        tt.clear();
        assert!(tt.probe(1).is_none());
        tt.store(1, data);
        tt.new_search();
        tt.probe(1);
        assert!(tt.probe(1).is_some());
    }

    #[test]
    fn test_new_search() {
        let tt = Tt::new();
        assert_eq!(tt.generation.get(), 0 << 2);
        tt.new_search();
        assert_eq!(tt.generation.get(), 1 << 2);
        for _ in 0..64 {
            tt.new_search();
        }
        assert_eq!(tt.generation.get(), 1 << 2);
    }
}
<commit_msg>removed stupid comments<commit_after>//! Implements a large hash-table that stores results of previously
//! performed searches ("transposition table").
//!
//! Chess programs, during their brute-force search, encounter the
//! same positions again and again, but from different sequences of
//! moves, which is called a "transposition". When the search
//! encounters a transposition, it is beneficial to "remember" what
//! was determined last time the position was examined, rather than
//! redoing the entire search again. For this reason, chess programs
//! have a transposition table, which is a large hash table storing
//! information about positions previously searched, how deeply they
//! were searched, and what we concluded about them.

use std;
use std::cell::{UnsafeCell, Cell};
use std::mem::transmute;
use std::num::Wrapping;
use basetypes::Value;
use chess_move::MoveDigest;

/// `BOUND_EXACT`, `BOUND_LOWER`, `BOUND_UPPER`, or `BOUND_NONE`.
///
/// For the majority of chess positions our evaluations will be more
/// or less inaccurate, and there is nothing we can do about it. But
/// sometimes we know that a given evaluation is probably inaccurate,
/// and we know the sign of the error. `BoundType` defines the
/// direction of such **known inaccuracies**.
///
/// * `BOUND_EXACT` means that the evaluation is exact (as far as we know).
///
/// * `BOUND_LOWER` means that the real value is greater or equal to
///    the evaluation (as far as we know).
///
/// * `BOUND_UPPER` means that the real value is lesser or equal to
///   the evaluation (as far as we know).
///
/// * `BOUND_NONE` means that the real value might be lesser, equal,
///   or grater than the evaluation.
pub type BoundType = u8;

pub const BOUND_NONE: BoundType = 0;
pub const BOUND_UPPER: BoundType = 0b10;
pub const BOUND_LOWER: BoundType = 0b01;
pub const BOUND_EXACT: BoundType = BOUND_UPPER | BOUND_LOWER;

/// Contains information about a particular position.
#[derive(Copy, Clone)]
pub struct TtEntry {
    move16: MoveDigest,
    value: Value,
    eval_value: Value,
    gen_bound: u8,
    depth: u8,
}

impl TtEntry {
    /// Creates a new instance.
    ///
    /// * `value` -- the value assigned to the position;
    ///
    /// * `bound` -- the accuracy of the assigned `value`;
    ///
    /// * `depth` -- the depth of search;
    ///
    /// * `move16` -- best or refutation move, or `0` if no move is
    ///   available;
    ///
    /// * `eval_value` -- the calculated static evaluation for the
    ///   position.
    pub fn new(value: Value,
               bound: BoundType,
               depth: u8,
               move16: MoveDigest,
               eval_value: Value)
               -> TtEntry {
        assert!(bound <= 0b11);
        assert!(depth < 127);
        TtEntry {
            move16: move16,
            value: value,
            eval_value: eval_value,
            gen_bound: bound, // Stores the entry's generation and the bound.
            depth: depth,
        }
    }

    #[inline(always)]
    pub fn value(&self) -> Value {
        self.value
    }

    #[inline(always)]
    pub fn bound(&self) -> BoundType {
        self.gen_bound & 0b11
    }

    #[inline(always)]
    pub fn depth(&self) -> u8 {
        self.depth
    }

    #[inline(always)]
    pub fn move16(&self) -> MoveDigest {
        self.move16
    }

    #[inline(always)]
    pub fn eval_value(&self) -> Value {
        self.eval_value
    }
}

/// Represents a record in the transposition table.
///
/// It consists of 16 bytes, and is laid out the following way:
///
/// * key        64 bit
/// * move16     16 bit
/// * value      16 bit
/// * eval value 16 bit
/// * generation  6 bit
/// * bound type  2 bit
/// * depth       8 bit
#[derive(Copy, Clone)]
struct Record {
    key: u64,
    data: TtEntry,
}

impl Default for Record {
    fn default() -> Record {
        Record {
            key: 0,
            data: unsafe { transmute(0u64) },
        }
    }
}

impl Record {
    /// Returns the contained data as one `u64` value.
    #[inline(always)]
    fn data_u64(&self) -> u64 {
        unsafe { transmute(self.data) }
    }

    /// Returns record's generation.
    #[inline(always)]
    fn generation(&self) -> u8 {
        self.data.gen_bound & 0b11111100
    }

    /// Updates record's generation.
    #[inline(always)]
    fn update_generation(&mut self, generation: u8) {
        assert_eq!(generation & 0b11, 0);

        // Since the `key` is saved XOR-ed with the data, when we
        // change the data, we have to change the stored `key` as
        // well.
        let old_data_u64 = self.data_u64();
        self.data.gen_bound = generation | self.data.bound();
        self.key ^= old_data_u64 ^ self.data_u64();
    }
}

/// A transposition table.
pub struct Tt {
    generation: Cell<u8>,
    cluster_count: usize,
    table: UnsafeCell<Vec<[Record; 4]>>,
}

impl Tt {
    /// Creates a new transposition table.
    ///
    /// The newly created table has the minimum possible size. Before
    /// using the new table for anything, `resize()` should be called
    /// on it, specifying the desired size.
    pub fn new() -> Tt {
        Tt {
            generation: Cell::new(0),
            cluster_count: 1,
            table: UnsafeCell::new(vec![Default::default()]),
        }
    }

    /// Resizes the transpositon table. All entries in the table will
    /// be lost.
    ///
    /// `size_mb` is the desired new size in Mbytes. If `size_mb` is
    /// not in the form "2**n", the new size of the transposition
    /// table will be as close as possible, but less than `size_mb`.
    pub fn resize(&mut self, size_mb: usize) {
        let requested_cluster_count = (size_mb * 1024 * 1024) / std::mem::size_of::<[Record; 4]>();

        // First, make sure `requested_cluster_count` is exceeded.
        let mut new_cluster_count = 1;
        while requested_cluster_count >= new_cluster_count {
            new_cluster_count <<= 1;
        }

        // Then make one step back, being careful so that the new
        // cluster count is not zero.
        if new_cluster_count > 1 {
            new_cluster_count >>= 1;
        } else {
            new_cluster_count = 1;
        }

        // Finally, reallocate the vector of clusters.
        if new_cluster_count != self.cluster_count {
            self.cluster_count = new_cluster_count;
            self.table = UnsafeCell::new(vec![Default::default(); new_cluster_count]);
        }
    }

    /// Returns the size of the transposition table in Mbytes.
    pub fn size(&self) -> usize {
        unsafe { &*self.table.get() }.len() * std::mem::size_of::<[Record; 4]>() / 1024 / 1024
    }

    /// Removes all entries in the table.
    pub fn clear(&self) {
        let table = unsafe { self.table.get().as_mut().unwrap() };
        for cluster in table {
            for record in cluster.iter_mut() {
                *record = Default::default();
            }
        }
        self.generation.set(0);
    }

    /// Signals that a new search is about to begin.
    ///
    /// Internally, the transposition table maintains a generation
    /// counter that is used to implement an efficient replacement
    /// strategy. This method increases this counter.
    pub fn new_search(&self) {
        // Note: The lowest 2 bits of the `generation` field are used
        // for the bound type.
        self.generation.set((Wrapping(self.generation.get()) + Wrapping(0b100)).0);
        assert_eq!(self.generation.get() & 0b11, 0);
    }

    /// Probes for data by a specific key.
    #[inline]
    pub fn probe(&self, key: u64) -> Option<TtEntry> {
        let cluster = unsafe { self.cluster_mut(key) };
        for record in cluster.iter_mut() {
            if record.key ^ record.data_u64() == key {
                // If `key` and `data` were written simultaneously by
                // different search instances with different keys,
                // this will yield in a mismatch of the above
                // comparison (except for the rare and inherent key
                // collisions).
                record.update_generation(self.generation.get());
                return Some(record.data);
            }
        }
        None
    }

    /// Peeks for data by a specific key.
    ///
    /// This method does the same as `probe`, except it does not
    /// update the generation of the entry. This is useful when we
    /// want to extract the primary variation from the the
    /// transposition table, without affecting the entries in the
    /// table.
    #[inline]
    pub fn peek(&self, key: u64) -> Option<TtEntry> {
        let cluster = unsafe { self.cluster_mut(key) };
        for record in cluster.iter_mut() {
            if record.key ^ record.data_u64() == key {
                return Some(record.data);
            }
        }
        None
    }

    /// Stores data by a specific key.
    ///
    /// After being stored, the data might be retrieved by
    /// `probe(key)`. This is not guaranteed though, because in the
    /// meantime it might have been overwritten.
    pub fn store(&self, key: u64, mut data: TtEntry) {
        // `store` and `probe` jointly implement a clever lock-less
        // hashing method. Rather than storing two disjoint items, the
        // key is stored XOR-ed with data, while data is stored
        // additionally as usual.

        // Set the entry's generation.
        data.gen_bound |= self.generation.get();

        // Choose a slot to which to write the data. (Each cluster has
        // 4 slots.)
        let mut cluster = unsafe { self.cluster_mut(key) };
        let mut replace_index = 0;
        let mut replace_score = 0xff;
        for (i, record) in cluster.iter_mut().enumerate() {
            // Check if this is an empty slot, or an old record for
            // the same key. If this this is the case we will use this
            // slot for the new record.
            if record.key == 0 || record.key ^ record.data_u64() == key {
                if data.move16 == 0 {
                    data.move16 = record.data.move16; // Preserve any existing move.
                }
                replace_index = i;
                break;
            }

            // Calculate the score for this record. If we can not find
            // an empty/old slot, the replaced record will be the
            // record with the lowest score.
            let record_score = self.calc_score(record);
            if record_score < replace_score {
                replace_index = i;
                replace_score = record_score;
            }
        }

        // Write the data to the chosen slot.
        unsafe {
            cluster.get_unchecked_mut(replace_index).key = key ^ transmute::<TtEntry, u64>(data);
            cluster.get_unchecked_mut(replace_index).data = data;
        }
    }

    // A helper method for `store`. It implements our replacement
    // strategy. It returns higher values for the records that are
    // move likely to save CPU work in the future.
    #[inline(always)]
    fn calc_score(&self, record: &Record) -> u8 {
        // Positions from the current generation are always scored
        // higher than positions from older generations.
        (if record.generation() == self.generation.get() {
            128
        } else {
            0
        })

        // Positions with higher search depth are scored higher.
        + record.data.depth()

        // Positions with exact evaluation are given slight advantage.
        + (if record.data.bound() == BOUND_EXACT {
            1
        } else {
            0
        })
    }

    // A helper method for `probe` and `store`. It gives the cluster
    // for a given key. (Each cluster can store up to 4 records.)
    #[inline]
    unsafe fn cluster_mut(&self, key: u64) -> &mut [Record; 4] {
        let cluster_index = (key & (self.cluster_count - 1) as u64) as usize;
        self.table.get().as_mut().unwrap().get_unchecked_mut(cluster_index)
    }
}

unsafe impl Sync for Tt {}

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

    #[test]
    fn test_cluster_size() {
        assert_eq!(std::mem::size_of::<[Record; 4]>(), 64);
        assert_eq!(std::mem::size_of::<Record>(), 16);
    }

    #[test]
    fn test_tt_resize() {
        let mut tt = Tt::new();
        assert_eq!(unsafe { &*tt.table.get() }.capacity(), 1);
        tt.resize(1);
        assert_eq!(tt.size(), 1);
        tt.clear();
    }

    #[test]
    fn test_store_and_probe() {
        let tt = Tt::new();
        assert!(tt.probe(1).is_none());
        let data = TtEntry::new(0, 0, 100, 666, 0);
        assert_eq!(data.depth(), 100);
        assert_eq!(data.move16(), 666);
        tt.store(1, data);
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        tt.store(1, TtEntry::new(0, 0, 100, 666, 0));
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        assert_eq!(tt.probe(1).unwrap().move16(), 666);
        for i in 2..100 {
            tt.store(i, TtEntry::new(i as i16, 0, i as u8, i as u16, i as i16));
        }
        assert_eq!(tt.probe(1).unwrap().depth(), 100);
        assert_eq!(tt.probe(99).unwrap().depth(), 99);
        assert_eq!(tt.probe(98).unwrap().depth(), 98);
        assert_eq!(tt.probe(97).unwrap().depth(), 97);
        tt.clear();
        assert!(tt.probe(1).is_none());
        tt.store(1, data);
        tt.new_search();
        tt.probe(1);
        assert!(tt.probe(1).is_some());
    }

    #[test]
    fn test_new_search() {
        let tt = Tt::new();
        assert_eq!(tt.generation.get(), 0 << 2);
        tt.new_search();
        assert_eq!(tt.generation.get(), 1 << 2);
        for _ in 0..64 {
            tt.new_search();
        }
        assert_eq!(tt.generation.get(), 1 << 2);
    }
}
<|endoftext|>


<commit_before>//! This module implements an efficient transposition table.

use std;
use std::cell::UnsafeCell;

#[derive(Default, Clone)]
struct Cluster {
    entries: [Entry; 4],
}

/// Represents transposition table entry.
///
/// It is 10 bytes, defined as below:
///
/// * key        16 bit
/// * move16     16 bit
/// * value      16 bit
/// * eval value 16 bit
/// * generation  6 bit
/// * bound type  2 bit
/// * depth       8 bit
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Entry {
    key: u64,
    move16: u16,
    value: i16,
    eval_value: i16,
    gen_bound: u8,
    depth: u8,
}

impl Default for Entry {
    fn default() -> Entry {
        Entry {
            key: 0,
            move16: 0,
            value: 0,
            eval_value: 0,
            gen_bound: 0,
            depth: 0,
        }
    }
}

impl Entry {
    fn new(key: u64,
           value: i16,
           bound: u8,
           depth: u8,
           move16: u16,
           generation: u8,
           eval_value: i16)
           -> Entry {
        Entry {
            key: key,
            move16: move16,
            value: value,
            eval_value: eval_value,
            gen_bound: generation | bound,
            depth: depth,
        }
    }

    #[inline(always)]
    fn key(&self) -> u64 {
        self.key
    }

    #[inline(always)]
    fn data(&self) -> u64 {
        self.key
    }

    #[inline(always)]
    fn move16(&self) -> u16 {
        self.move16
    }

    #[inline(always)]
    fn value(&self) -> i16 {
        self.value
    }

    #[inline(always)]
    fn eval_value(&self) -> i16 {
        self.eval_value
    }

    #[inline(always)]
    fn depth(&self) -> u8 {
        self.depth
    }

    #[inline(always)]
    fn bound(&self) -> u8 {
        self.gen_bound & 0b11
    }
}

pub struct TranspositionTable {
    generation: u8,
    cluster_count: usize,
    table: UnsafeCell<Vec<Cluster>>,
}

impl TranspositionTable {
    pub fn new() -> TranspositionTable {
        TranspositionTable {
            generation: 0,
            cluster_count: 1,
            table: UnsafeCell::new(vec![Default::default()]),
        }
    }

    pub fn new_search(&mut self) {
        self.generation += 0b100;  // Lower 2 bits are used by bound type
    }

    pub fn resize(&mut self, size_mb: usize) {
        // The cluster count should be in the form "2**n", so the best
        // we can do is to ensure that the new cluster count will be
        // as close as possible but no greater than the requested one.
        let requested_cluster_count = (size_mb * 1024 * 1024) / std::mem::size_of::<Cluster>();

        // First we make sure `requested_cluster_count` is exceeded.
        let mut new_cluster_count = 1;
        while requested_cluster_count >= new_cluster_count {
            new_cluster_count <<= 1;
        }

        // Then we make one step back, making sure that the new
        // cluster count is not zero.
        if new_cluster_count > 1 {
            new_cluster_count >>= 1;
        } else {
            new_cluster_count = 1;
        }
        if new_cluster_count != self.cluster_count {
            self.cluster_count = new_cluster_count;
            self.table = UnsafeCell::new(vec![Default::default(); new_cluster_count]);
        }
    }

    pub fn clear(&mut self) {
        self.table = UnsafeCell::new(vec![Default::default(); self.cluster_count]);
    }

    pub fn probe(&self, key: u64) -> Option<Entry> {
        let cluster: &mut Cluster = unsafe {
            (&mut *self.table.get()).get_unchecked_mut(self.cluster_index(key))
        };

        for i in 0..4 {
            let entry = cluster.entries[i];
            if entry.key() ^ entry.data() == key {
                return Some(entry);
            }
        }
        None
    }

    #[inline(always)]
    fn cluster_index(&self, key: u64) -> usize {
        (key & (self.cluster_count - 1) as u64) as usize
    }

    // const TTEntry* TranspositionTable::probe(const Key key) const {

    //   TTEntry* tte = first_entry(key);
    //   uint16_t key16 = key >> 48;

    //   for (unsigned i = 0; i < TTClusterSize; ++i, ++tte)
    //       if (tte->key16 == key16)
    //       {
    //           tte->genBound8 = generation | tte->bound(); // Refresh
    //           return tte;
    //       }

    //   return NULL;
    // }
}

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

    #[test]
    fn test_cluster_size() {
        assert_eq!(std::mem::size_of::<Cluster>(), 64);
        assert_eq!(std::mem::size_of::<Entry>(), 16);
    }

    #[test]
    fn test_tt_resize() {
        let mut tt = TranspositionTable::new();
        assert_eq!(unsafe { &*tt.table.get() }.capacity(), 1);
        tt.resize(1);
        assert_eq!(unsafe { &*tt.table.get() }.capacity(),
                   1024 * 1024 / std::mem::size_of::<Cluster>());
        tt.clear();
    }
}
<commit_msg>more work on tt.rs<commit_after>//! This module implements an efficient transposition table.

use std;
use std::cell::UnsafeCell;
use std::mem::transmute;

#[derive(Copy, Clone)]
pub struct EntryData {
    move16: u16,
    value: i16,
    eval_value: i16,
    gen_bound: u8,
    depth: u8,
}

impl EntryData {
    #[inline(always)]
    pub fn move16(&self) -> u16 {
        self.move16
    }

    #[inline(always)]
    pub fn value(&self) -> i16 {
        self.value
    }

    #[inline(always)]
    pub fn eval_value(&self) -> i16 {
        self.eval_value
    }

    #[inline(always)]
    pub fn depth(&self) -> u8 {
        self.depth
    }

    #[inline(always)]
    pub fn bound(&self) -> u8 {
        self.gen_bound & 0b11
    }
}

// Represents transposition table entry.
//
// It is 16 bytes, defined as below:
//
// * key        64 bit
// * move16     16 bit
// * value      16 bit
// * eval value 16 bit
// * generation  6 bit
// * bound type  2 bit
// * depth       8 bit
#[derive(Copy, Clone)]
struct Entry {
    key: u64,
    data: EntryData,
}

impl Default for Entry {
    fn default() -> Entry {
        Entry {
            key: 0,
            data: unsafe { transmute(0u64) },
        }
    }
}

impl Entry {
    fn new(key: u64,
           value: i16,
           bound: u8,
           depth: u8,
           move16: u16,
           generation: u8,
           eval_value: i16)
           -> Entry {
        Entry {
            key: key,
            data: EntryData {
                move16: move16,
                value: value,
                eval_value: eval_value,
                gen_bound: generation | bound,
                depth: depth, // TODO: DEPTH_NONE?
            },
        }
    }

    #[inline(always)]
    fn key(&self) -> u64 {
        self.key
    }

    #[inline(always)]
    fn data(&self) -> u64 {
        unsafe { transmute(self.data) }
    }

    #[inline(always)]
    fn generation(&self) -> u8 {
        self.data.gen_bound & 0b11111100
    }
}

#[derive(Default, Clone)]
struct Cluster {
    entries: [Entry; 4],
}

pub struct TranspositionTable {
    generation: u8,
    cluster_count: usize,
    table: UnsafeCell<Vec<Cluster>>,
}

impl TranspositionTable {
    pub fn new() -> TranspositionTable {
        TranspositionTable {
            generation: 0,
            cluster_count: 1,
            table: UnsafeCell::new(vec![Default::default()]),
        }
    }

    pub fn new_search(&mut self) {
        self.generation += 0b100;  // Lower 2 bits are used by bound type
    }

    pub fn resize(&mut self, size_mb: usize) {
        // The cluster count should be in the form "2**n", so the best
        // we can do is to ensure that the new cluster count will be
        // as close as possible but no greater than the requested one.
        let requested_cluster_count = (size_mb * 1024 * 1024) / std::mem::size_of::<Cluster>();

        // First we make sure `requested_cluster_count` is exceeded.
        let mut new_cluster_count = 1;
        while requested_cluster_count >= new_cluster_count {
            new_cluster_count <<= 1;
        }

        // Then we make one step back, making sure that the new
        // cluster count is not zero.
        if new_cluster_count > 1 {
            new_cluster_count >>= 1;
        } else {
            new_cluster_count = 1;
        }
        if new_cluster_count != self.cluster_count {
            self.cluster_count = new_cluster_count;
            self.table = UnsafeCell::new(vec![Default::default(); new_cluster_count]);
        }
    }

    pub fn clear(&mut self) {
        self.table = UnsafeCell::new(vec![Default::default(); self.cluster_count]);
    }

    pub fn probe(&self, key: u64) -> Option<EntryData> {
        let cluster = self.cluster_mut(key);
        for entry in cluster.entries.iter_mut() {
            if entry.key() ^ entry.data() == key {
                // Transposition table hit. Refresh entry's generation
                // and return the entry.
                entry.data.gen_bound = self.generation | entry.data.bound();
                return Some(entry.data);
            }
        }
        // Transposition table miss.
        None
    }

    pub fn store(&self, key: u64, mut data: EntryData) {
        let mut entries = self.cluster_mut(key).entries;
        let mut replace_index = 0;
        for i in 0..4 {
            let e = entries[i];
            if e.key() == 0 || e.key() ^ e.data() == key {
                // This is either an empty entry, or we overwrite an
                // old entry for the same key.
                if data.move16 == 0 {
                    // Preserve any existing move.
                    data.move16 = e.data.move16;
                }
                replace_index = i;
                break;
            }
            // Implement replace strategy
            // if (e.generation() == self.generation || e.data.bound() == Bound::BOUND_EXACT) -
            //    (entries[replace_index].generation() == self.generation) -
            //    (e.data.depth < entries[replace_index].data.depth) < 0 {
            //     replace_index = i;

            // }
        }
        unsafe {
            entries.get_unchecked_mut(replace_index).key = key ^ transmute::<EntryData, u64>(data);
            entries.get_unchecked_mut(replace_index).data = data;
        }
    }

    #[inline(always)]
    fn cluster_mut(&self, key: u64) -> &mut Cluster {
        let cluster_index = (key & (self.cluster_count - 1) as u64) as usize;
        unsafe { (&mut *self.table.get()).get_unchecked_mut(cluster_index) }
    }

    // void TranspositionTable::store(const Key key, Value v, Bound b, Depth d, Move m, Value statV) {

    //   TTEntry *tte, *replace;
    //   uint16_t key16 = key >> 48; // Use the high 16 bits as key inside the cluster

    // tte = replace = first_entry(key);

    //   for (unsigned i = 0; i < TTClusterSize; ++i, ++tte)
    //   {
    //       if (!tte->key16 || tte->key16 == key16) // Empty or overwrite old
    //       {
    //           if (!m)
    //               m = tte->move(); // Preserve any existing ttMove

    //           replace = tte;
    //           break;
    //       }

    //       // Implement replace strategy
    //       if (  ((    tte->genBound8 & 0xFC) == generation || tte->bound() == BOUND_EXACT)
    //           - ((replace->genBound8 & 0xFC) == generation)
    //           - (tte->depth8 < replace->depth8) < 0)
    //           replace = tte;
    //   }

    //   replace->save(key16, v, b, d, m, generation, statV);
    // }

    // const TTEntry* TranspositionTable::probe(const Key key) const {

    //   TTEntry* tte = first_entry(key);
    //   uint16_t key16 = key >> 48;

    //   for (unsigned i = 0; i < TTClusterSize; ++i, ++tte)
    //       if (tte->key16 == key16)
    //       {
    //           tte->genBound8 = generation | tte->bound(); // Refresh
    //           return tte;
    //       }

    //   return NULL;
    // }
}

pub enum Bound {
    BOUND_NONE = 0,
    BOUND_UPPER = 1,
    BOUND_LOWER = 2,
    BOUND_EXACT = 3,
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::{Cluster, Entry};
    use std;
    use basetypes::*;

    #[test]
    fn test_cluster_size() {
        assert_eq!(std::mem::size_of::<Cluster>(), 64);
        assert_eq!(std::mem::size_of::<Entry>(), 16);
    }

    #[test]
    fn test_tt_resize() {
        let mut tt = TranspositionTable::new();
        assert_eq!(unsafe { &*tt.table.get() }.capacity(), 1);
        tt.resize(1);
        assert_eq!(unsafe { &*tt.table.get() }.capacity(),
                   1024 * 1024 / std::mem::size_of::<Cluster>());
        tt.clear();
    }
}
<|endoftext|>


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

//! Volume Groups

use std::io::Result;
use std::io::Error;
use std::io::ErrorKind::Other;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::str::FromStr;
use std::borrow::Cow;

use time::now;
use nix::sys::utsname::uname;

use lv::{LV, Segment};
use pv::{PV, Device};
use pvlabel::PvHeader;
use parser::{LvmTextMap, Entry};
use lvmetad;
use dm::DM;
use util::{align_to, make_uuid};

/// A Volume Group.
#[derive(Debug, PartialEq, Clone)]
pub struct VG {
    /// Name.
    pub name: String,
    /// Uuid.
    pub id: String,
    /// The generation of metadata this VG represents.
    pub seqno: u64,
    /// Always "LVM2".
    pub format: String,
    /// Status.
    pub status: Vec<String>,
    /// Flags.
    pub flags: Vec<String>,
    /// Size of each extent, in 512-byte sectors.
    pub extent_size: u64,
    /// Maximum number of LVs, 0 means no limit.
    pub max_lv: u64,
    /// Maximum number of PVs, 0 means no limit.
    pub max_pv: u64,
    /// How many metadata copies (?)
    pub metadata_copies: u64,
    /// Physical Volumes within this volume group.
    pub pvs: BTreeMap<String, PV>,
    /// Logical Volumes within this volume group.
    pub lvs: BTreeMap<String, LV>,
}

impl VG {
    /// The total number of extents in use in the volume group.
    pub fn extents_in_use(&self) -> u64 {
        self.lvs
            .values()
            .map(|x| x.used_extents())
            .sum()
    }

    /// The total number of free extents in the volume group.
    pub fn extents_free(&self) -> u64 {
        self.extents() - self.extents_in_use()
    }

    /// The total number of extents in the volume group.
    pub fn extents(&self) -> u64 {
        self.pvs
            .values()
            .map(|x| x.pe_count)
            .sum()
    }

    // Recursively walk DM deps to see if device is present
    fn depends_on(dev: Device, dm_majors: &BTreeSet<u32>, dm: &DM) -> bool {
        if !dm_majors.contains(&dev.major) {
            return false;
        }

        if let Ok(dep_list) = dm.list_deps(dev) {
            for d in dep_list {
                if d == dev {
                    return true;
                } else if Self::depends_on(d, dm_majors, dm) {
                    return true;
                }
            }
        }

        false
    }

    /// Add a non-affiliated PV to this VG.
    pub fn add_pv(&mut self, pvh: &PvHeader) -> Result<()> {
        // add_pv_to_vg
        // check pv is not on an LV from the vg:
        // 1) is pv's major a devicemapper major?
        // 2) equiv. of dev_manager_device_uses_vg()

        let dm_majors = DM::dm_majors();
        let dev = try!(Device::from_str(&pvh.dev_path.to_string_lossy()));
        {
            let dm = try!(DM::new(&self));
            if Self::depends_on(dev, &dm_majors, &dm) {
                return Err(Error::new(Other, "Dependency loops prohibited"));
            }
        }

        // check pv is not already in the VG or another VG
        // Does it have text metadata??
        if let Ok(metadata) = pvh.read_metadata() {

            // Find the textmap for the vg, among all the other stuff.
            // (It's the only textmap.)
            let mut vg_name = Cow::Borrowed("<unknown>");
            for (key, value) in metadata {
                match value {
                    Entry::TextMap(_) => {
                        vg_name = Cow::Owned(key);
                        break
                    },
                    _ => {}
                }
            }

            return Err(Error::new(Other, format!("PV already in VG {}", vg_name)));
        }

        let da = try!(pvh.data_areas.get(0)
                      .ok_or(Error::new(Other, "Could not find data area in PV")));

        // figure out how many extents fit in the PV's data area
        // pe_start aligned to extent size
        let pe_start = align_to(da.offset as usize, self.extent_size as usize) as u64;
        let mda1_size = match pvh.metadata_areas.get(1) {
            Some(pvarea) => pvarea.size,
            None => 0,
        };
        let area_size = pvh.size - pe_start - mda1_size;
        let pe_count = area_size / self.extent_size;

        let name = format!("pv{}", self.pvs.len());

        // make a PV and add it to self
        let pv = PV {
            name: name.clone(),
            id: pvh.uuid.clone(),
            device: dev,
            status: vec!["ALLOCATABLE".to_string()],
            flags: Vec::new(),
            dev_size: pvh.size,
            pe_start: pe_start,
            pe_count: pe_count,
        };

        self.pvs.insert(name, pv);

        self.commit()
    }

    /// Create a new linear logical volume in the volume group.
    pub fn new_linear_lv(&mut self, name: &str, extent_size: u64) -> Result<()> {
        if self.lvs.contains_key(name) {
            return Err(Error::new(Other, "LV already exists"));
        }

        let mut contig_area = None;
        for (pvname, areas) in self.free_areas() {
            for (start, len) in areas {
                if len >= extent_size {
                    contig_area = Some((pvname, start));
                    break;
                }
            }
        }

        // we don't support multiple segments yet
        let (pv_with_area, area_start) = match contig_area {
            None => return Err(Error::new(Other, "no contiguous area for new LV")),
            Some(x) => x,
        };

        let segment = Segment {
            name: "segment1".to_string(),
            start_extent: 0,
            extent_count: extent_size,
            ty: "striped".to_string(),
            stripes: vec![(pv_with_area, area_start)],
        };

        let mut lv = LV {
            name: name.to_string(),
            id: make_uuid(),
            status: vec!["READ".to_string(),
                         "WRITE".to_string(),
                         "VISIBLE".to_string()],
            flags: Vec::new(),
            creation_host: uname().nodename().to_string(),
            creation_time: now().to_timespec().sec,
            segments: vec![segment],
            device: None,
        };

        // poke dm and tell it about a new device
        {
            let dm = try!(DM::new(self));
            try!(dm.activate_device(&mut lv));
        }

        self.lvs.insert(name.to_string(), lv);

        self.commit()
    }

    /// Destroy a logical volume.
    pub fn lv_remove(&mut self, name: &str) -> Result<()> {
        match self.lvs.remove(name) {
            None => Err(Error::new(Other, "LV not found in VG")),
            Some(mut lv) => {
                {
                    let dm = try!(DM::new(self));
                    try!(dm.deactivate_device(&mut lv));
                }

                self.commit()
            },
        }
    }

    fn commit(&mut self) -> Result<()> {
        let map: LvmTextMap = self.clone().into();

        let mut disk_map = LvmTextMap::new();
        disk_map.insert("contents".to_string(),
                        Entry::String("Text Format Volume Group".to_string()));
        disk_map.insert("version".to_string(), Entry::Number(1));
        disk_map.insert("description".to_string(), Entry::String("".to_string()));
        disk_map.insert("creation_host".to_string(),
                        Entry::String(uname().nodename().to_string()));
        disk_map.insert("creation_time".to_string(),
                        Entry::Number(now().to_timespec().sec));
        disk_map.insert(self.name.clone(), Entry::TextMap(Box::new(map.clone())));

        // TODO: atomicity of updating pvs, metad, dm
        for pv in self.pvs.values() {
            if let Some(path) = pv.device.path() {
                let mut pvheader = PvHeader::find_in_dev(&path)
                    .expect("could not find pvheader");

                try!(pvheader.write_metadata(&disk_map));
            }
        }

        lvmetad::vg_update(&self.name, &map)
    }

    // Returns e.g. {"pv0": {0: 45, 47: 100, 100: 200} }
    // This means extents 0-44 are used, 45 and 46 are not,
    // 47-99 are used, then 100-199 are used.
    //
    // Adjacent used areas are not merged.
    //
    // PVs with no used areas are not in the outer map at all.
    //
    fn used_areas(&self) -> BTreeMap<String, BTreeMap<u64, u64>> {
        let mut used_map = BTreeMap::new();

        for lv in self.lvs.values() {
            for seg in &lv.segments {
                for &(ref pvname, start) in &seg.stripes {
                    used_map.entry(pvname.to_string())
                        .or_insert(BTreeMap::new())
                        .insert(start as u64, seg.extent_count);
                }
            }
        }

        used_map
    }

    // Returns e.g. {"pv0": {45: 47, 200: 1000} }
    // (assuming pv0 has 1000 extents)
    //
    fn free_areas(&self) -> BTreeMap<String, BTreeMap<u64, u64>> {
        let mut free_map = BTreeMap::new();

        for (pvname, mut area_map) in self.used_areas() {

            // Insert an entry to mark the end of the PV so the fold works
            // correctly
            let pv = self.pvs.get(&pvname)
                .expect("area map name refers to nonexistent PV");
            area_map.insert(pv.pe_count, 0);

            area_map.iter()
                .fold(0, |prev_end, (start, len)| {
                    if prev_end < *start {
                        free_map.entry(pvname.clone())
                            .or_insert(BTreeMap::new())
                            .insert(prev_end, start-prev_end);
                    }
                    start + len
                });
        }

        // Also return completely-unused PVs
        for (pvname, pv) in &self.pvs {
            if !free_map.contains_key(pvname) {
                let mut map = BTreeMap::new();
                map.insert(0, pv.pe_count);
                free_map.insert(pvname.clone(), map);
            }
        }

        free_map
    }
}

impl From<VG> for LvmTextMap {
    fn from(vg: VG) -> Self {
        let mut map = LvmTextMap::new();

        map.insert("id".to_string(), Entry::String(vg.id));
        map.insert("seqno".to_string(),
                   Entry::Number(vg.seqno as i64 + 1));
        map.insert("format".to_string(), Entry::String(vg.format));

        map.insert("max_pv".to_string(), Entry::Number(0));
        map.insert("max_lv".to_string(), Entry::Number(0));

        map.insert("status".to_string(),
                   Entry::List(
                       Box::new(
                           vg.status
                               .into_iter()
                               .map(|x| Entry::String(x))
                               .collect())));

        map.insert("flags".to_string(),
                   Entry::List(
                       Box::new(
                           vg.flags
                               .into_iter()
                               .map(|x| Entry::String(x))
                               .collect())));

        map.insert("extent_size".to_string(),
                   Entry::Number(vg.extent_size as i64));
        map.insert("metadata_copies".to_string(),
                   Entry::Number(vg.metadata_copies as i64));
        map.insert("physical_volumes".to_string(),
                   Entry::TextMap(
                       Box::new(
                           vg.pvs
                               .into_iter()
                               .map(|(k, v)|
                                    (k, Entry::TextMap(Box::new(v.into()))))
                               .collect())));

        map.insert("logical_volumes".to_string(),
                   Entry::TextMap(
                       Box::new(
                           vg.lvs
                               .into_iter()
                               .map(|(k, v)|
                                    (k, Entry::TextMap(Box::new(v.into()))))
                               .collect())));

        map
    }
}
<commit_msg>Fix comments and whitespace in vg.rs<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! Volume Groups

use std::io::Result;
use std::io::Error;
use std::io::ErrorKind::Other;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::str::FromStr;
use std::borrow::Cow;

use time::now;
use nix::sys::utsname::uname;

use lv::{LV, Segment};
use pv::{PV, Device};
use pvlabel::PvHeader;
use parser::{LvmTextMap, Entry};
use lvmetad;
use dm::DM;
use util::{align_to, make_uuid};

/// A Volume Group.
#[derive(Debug, PartialEq, Clone)]
pub struct VG {
    /// Name.
    pub name: String,
    /// Uuid.
    pub id: String,
    /// The generation of metadata this VG represents.
    pub seqno: u64,
    /// Always "LVM2".
    pub format: String,
    /// Status.
    pub status: Vec<String>,
    /// Flags.
    pub flags: Vec<String>,
    /// Size of each extent, in 512-byte sectors.
    pub extent_size: u64,
    /// Maximum number of LVs, 0 means no limit.
    pub max_lv: u64,
    /// Maximum number of PVs, 0 means no limit.
    pub max_pv: u64,
    /// How many metadata copies (?)
    pub metadata_copies: u64,
    /// Physical Volumes within this volume group.
    pub pvs: BTreeMap<String, PV>,
    /// Logical Volumes within this volume group.
    pub lvs: BTreeMap<String, LV>,
}

impl VG {
    /// The total number of extents in use in the volume group.
    pub fn extents_in_use(&self) -> u64 {
        self.lvs
            .values()
            .map(|x| x.used_extents())
            .sum()
    }

    /// The total number of free extents in the volume group.
    pub fn extents_free(&self) -> u64 {
        self.extents() - self.extents_in_use()
    }

    /// The total number of extents in the volume group.
    pub fn extents(&self) -> u64 {
        self.pvs
            .values()
            .map(|x| x.pe_count)
            .sum()
    }

    // Recursively walk DM deps to see if device is present
    fn depends_on(dev: Device, dm_majors: &BTreeSet<u32>, dm: &DM) -> bool {
        if !dm_majors.contains(&dev.major) {
            return false;
        }

        if let Ok(dep_list) = dm.list_deps(dev) {
            for d in dep_list {
                if d == dev {
                    return true;
                } else if Self::depends_on(d, dm_majors, dm) {
                    return true;
                }
            }
        }

        false
    }

    /// Add a non-affiliated PV to this VG.
    pub fn add_pv(&mut self, pvh: &PvHeader) -> Result<()> {
        // Check pv is not on an LV from the vg:
        // 1) is pv's major a devicemapper major?
        // 2) Walk dm deps (equiv. of LVM2 dev_manager_device_uses_vg)
        let dm_majors = DM::dm_majors();
        let dev = try!(Device::from_str(&pvh.dev_path.to_string_lossy()));
        {
            let dm = try!(DM::new(&self));
            if Self::depends_on(dev, &dm_majors, &dm) {
                return Err(Error::new(Other, "Dependency loops prohibited"));
            }
        }

        // check pv is not already in the VG or another VG
        // Does it have text metadata??
        if let Ok(metadata) = pvh.read_metadata() {
            // Find the textmap for the vg, among all the other stuff.
            // (It's the only textmap.)
            let mut vg_name = Cow::Borrowed("<unknown>");
            for (key, value) in metadata {
                match value {
                    Entry::TextMap(_) => {
                        vg_name = Cow::Owned(key);
                        break
                    },
                    _ => {}
                }
            }

            return Err(Error::new(Other, format!("PV already in VG {}", vg_name)));
        }

        let da = try!(pvh.data_areas.get(0)
                      .ok_or(Error::new(Other, "Could not find data area in PV")));

        // figure out how many extents fit in the PV's data area
        // pe_start aligned to extent size
        let pe_start = align_to(da.offset as usize, self.extent_size as usize) as u64;
        let mda1_size = match pvh.metadata_areas.get(1) {
            Some(pvarea) => pvarea.size,
            None => 0,
        };
        let area_size = pvh.size - pe_start - mda1_size;
        let pe_count = area_size / self.extent_size;

        let name = format!("pv{}", self.pvs.len());

        // make a PV and add it to self
        let pv = PV {
            name: name.clone(),
            id: pvh.uuid.clone(),
            device: dev,
            status: vec!["ALLOCATABLE".to_string()],
            flags: Vec::new(),
            dev_size: pvh.size,
            pe_start: pe_start,
            pe_count: pe_count,
        };

        self.pvs.insert(name, pv);

        self.commit()
    }

    /// Create a new linear logical volume in the volume group.
    pub fn new_linear_lv(&mut self, name: &str, extent_size: u64) -> Result<()> {
        if self.lvs.contains_key(name) {
            return Err(Error::new(Other, "LV already exists"));
        }

        let mut contig_area = None;
        for (pvname, areas) in self.free_areas() {
            for (start, len) in areas {
                if len >= extent_size {
                    contig_area = Some((pvname, start));
                    break;
                }
            }
        }

        // we don't support multiple segments yet
        let (pv_with_area, area_start) = match contig_area {
            None => return Err(Error::new(Other, "no contiguous area for new LV")),
            Some(x) => x,
        };

        let segment = Segment {
            name: "segment1".to_string(),
            start_extent: 0,
            extent_count: extent_size,
            ty: "striped".to_string(),
            stripes: vec![(pv_with_area, area_start)],
        };

        let mut lv = LV {
            name: name.to_string(),
            id: make_uuid(),
            status: vec!["READ".to_string(),
                         "WRITE".to_string(),
                         "VISIBLE".to_string()],
            flags: Vec::new(),
            creation_host: uname().nodename().to_string(),
            creation_time: now().to_timespec().sec,
            segments: vec![segment],
            device: None,
        };

        // poke dm and tell it about a new device
        {
            let dm = try!(DM::new(self));
            try!(dm.activate_device(&mut lv));
        }

        self.lvs.insert(name.to_string(), lv);

        self.commit()
    }

    /// Destroy a logical volume.
    pub fn lv_remove(&mut self, name: &str) -> Result<()> {
        match self.lvs.remove(name) {
            None => Err(Error::new(Other, "LV not found in VG")),
            Some(mut lv) => {
                {
                    let dm = try!(DM::new(self));
                    try!(dm.deactivate_device(&mut lv));
                }

                self.commit()
            },
        }
    }

    fn commit(&mut self) -> Result<()> {
        let map: LvmTextMap = self.clone().into();

        let mut disk_map = LvmTextMap::new();
        disk_map.insert("contents".to_string(),
                        Entry::String("Text Format Volume Group".to_string()));
        disk_map.insert("version".to_string(), Entry::Number(1));
        disk_map.insert("description".to_string(), Entry::String("".to_string()));
        disk_map.insert("creation_host".to_string(),
                        Entry::String(uname().nodename().to_string()));
        disk_map.insert("creation_time".to_string(),
                        Entry::Number(now().to_timespec().sec));
        disk_map.insert(self.name.clone(), Entry::TextMap(Box::new(map.clone())));

        // TODO: atomicity of updating pvs, metad, dm
        for pv in self.pvs.values() {
            if let Some(path) = pv.device.path() {
                let mut pvheader = PvHeader::find_in_dev(&path)
                    .expect("could not find pvheader");

                try!(pvheader.write_metadata(&disk_map));
            }
        }

        lvmetad::vg_update(&self.name, &map)
    }

    // Returns e.g. {"pv0": {0: 45, 47: 100, 100: 200} }
    // This means extents 0-44 are used, 45 and 46 are not,
    // 47-99 are used, then 100-199 are used.
    //
    // Adjacent used areas are not merged.
    //
    // PVs with no used areas are not in the outer map at all.
    //
    fn used_areas(&self) -> BTreeMap<String, BTreeMap<u64, u64>> {
        let mut used_map = BTreeMap::new();

        for lv in self.lvs.values() {
            for seg in &lv.segments {
                for &(ref pvname, start) in &seg.stripes {
                    used_map.entry(pvname.to_string())
                        .or_insert(BTreeMap::new())
                        .insert(start as u64, seg.extent_count);
                }
            }
        }

        used_map
    }

    // Returns e.g. {"pv0": {45: 47, 200: 1000} }
    // (assuming pv0 has 1000 extents)
    //
    fn free_areas(&self) -> BTreeMap<String, BTreeMap<u64, u64>> {
        let mut free_map = BTreeMap::new();

        for (pvname, mut area_map) in self.used_areas() {

            // Insert an entry to mark the end of the PV so the fold works
            // correctly
            let pv = self.pvs.get(&pvname)
                .expect("area map name refers to nonexistent PV");
            area_map.insert(pv.pe_count, 0);

            area_map.iter()
                .fold(0, |prev_end, (start, len)| {
                    if prev_end < *start {
                        free_map.entry(pvname.clone())
                            .or_insert(BTreeMap::new())
                            .insert(prev_end, start-prev_end);
                    }
                    start + len
                });
        }

        // Also return completely-unused PVs
        for (pvname, pv) in &self.pvs {
            if !free_map.contains_key(pvname) {
                let mut map = BTreeMap::new();
                map.insert(0, pv.pe_count);
                free_map.insert(pvname.clone(), map);
            }
        }

        free_map
    }
}

impl From<VG> for LvmTextMap {
    fn from(vg: VG) -> Self {
        let mut map = LvmTextMap::new();

        map.insert("id".to_string(), Entry::String(vg.id));
        map.insert("seqno".to_string(),
                   Entry::Number(vg.seqno as i64 + 1));
        map.insert("format".to_string(), Entry::String(vg.format));

        map.insert("max_pv".to_string(), Entry::Number(0));
        map.insert("max_lv".to_string(), Entry::Number(0));

        map.insert("status".to_string(),
                   Entry::List(
                       Box::new(
                           vg.status
                               .into_iter()
                               .map(|x| Entry::String(x))
                               .collect())));

        map.insert("flags".to_string(),
                   Entry::List(
                       Box::new(
                           vg.flags
                               .into_iter()
                               .map(|x| Entry::String(x))
                               .collect())));

        map.insert("extent_size".to_string(),
                   Entry::Number(vg.extent_size as i64));
        map.insert("metadata_copies".to_string(),
                   Entry::Number(vg.metadata_copies as i64));
        map.insert("physical_volumes".to_string(),
                   Entry::TextMap(
                       Box::new(
                           vg.pvs
                               .into_iter()
                               .map(|(k, v)|
                                    (k, Entry::TextMap(Box::new(v.into()))))
                               .collect())));

        map.insert("logical_volumes".to_string(),
                   Entry::TextMap(
                       Box::new(
                           vg.lvs
                               .into_iter()
                               .map(|(k, v)|
                                    (k, Entry::TextMap(Box::new(v.into()))))
                               .collect())));

        map
    }
}
<|endoftext|>


<commit_before>// variables1.rs
// Make me compile! Execute the command `rustlings hint variables1` if you want a hint :)

// About this `I AM NOT DONE` thing:
// We sometimes encourage you to keep trying things on a given exercise,
// even after you already figured it out. If you got everything working and
// feel ready for the next exercise, you the `I AM NOT DONE` comment below.

// I AM NOT DONE

fn main() {
    x = 5;
    println!("x has the value {}", x);
}
<commit_msg>fix(variables1): Correct wrong word in comment<commit_after>// variables1.rs
// Make me compile! Execute the command `rustlings hint variables1` if you want a hint :)

// About this `I AM NOT DONE` thing:
// We sometimes encourage you to keep trying things on a given exercise,
// even after you already figured it out. If you got everything working and
// feel ready for the next exercise, remove the `I AM NOT DONE` comment below.

// I AM NOT DONE

fn main() {
    x = 5;
    println!("x has the value {}", x);
}
<|endoftext|>


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

use std::net::SocketAddr;
use std::sync::{Arc, RwLock};
use std::thread;

use chain::{self, ChainAdapter};
use core::core::{self, Output};
use core::core::block::BlockHeader;
use core::core::hash::{Hash, Hashed};
use core::core::target::Difficulty;
use p2p::{self, NetAdapter, Server, PeerStore, PeerData, State};
use pool;
use secp::pedersen::Commitment;
use util::OneTime;
use store;
use sync;
use util::LOGGER;
use core::global::{MiningParameterMode, MINING_PARAMETER_MODE};

/// Implementation of the NetAdapter for the blockchain. Gets notified when new
/// blocks and transactions are received and forwards to the chain and pool
/// implementations.
pub struct NetToChainAdapter {
	chain: Arc<chain::Chain>,
	peer_store: Arc<PeerStore>,
	tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,

	syncer: OneTime<Arc<sync::Syncer>>,
}

impl NetAdapter for NetToChainAdapter {
	fn total_difficulty(&self) -> Difficulty {
		self.chain.total_difficulty()
	}

	fn transaction_received(&self, tx: core::Transaction) {
		let source = pool::TxSource {
			debug_name: "p2p".to_string(),
			identifier: "?.?.?.?".to_string(),
		};
		if let Err(e) = self.tx_pool.write().unwrap().add_to_memory_pool(source, tx) {
			error!(LOGGER, "Transaction rejected: {:?}", e);
		}
	}

	fn block_received(&self, b: core::Block) {
		let bhash = b.hash();
		debug!(
			LOGGER,
			"Received block {} from network, going to process.",
			bhash
		);

		// pushing the new block through the chain pipeline
		let res = self.chain.process_block(b, self.chain_opts());

		if let Err(e) = res {
			debug!(LOGGER, "Block {} refused by chain: {:?}", bhash, e);
		}

		if self.syncer.borrow().syncing() {
			self.syncer.borrow().block_received(bhash);
		}
	}

	fn headers_received(&self, bhs: Vec<core::BlockHeader>) {
		// try to add each header to our header chain
		let mut added_hs = vec![];
		for bh in bhs {
			let res = self.chain.process_block_header(&bh, self.chain_opts());
			match res {
				Ok(_) => {
					added_hs.push(bh.hash());
				}
				Err(chain::Error::Unfit(s)) => {
					info!(
						LOGGER,
						"Received unfit block header {} at {}: {}.",
						bh.hash(),
						bh.height,
						s
					);
				}
				Err(chain::Error::StoreErr(e)) => {
					error!(
						LOGGER,
						"Store error processing block header {}: {:?}",
						bh.hash(),
						e
					);
					return;
				}
				Err(e) => {
					info!(LOGGER, "Invalid block header {}: {:?}.", bh.hash(), e);
					// TODO penalize peer somehow
				}
			}
		}
		info!(
			LOGGER,
			"Added {} headers to the header chain.",
			added_hs.len()
		);

		if self.syncer.borrow().syncing() {
			self.syncer.borrow().headers_received(added_hs);
		}
	}

	fn locate_headers(&self, locator: Vec<Hash>) -> Vec<core::BlockHeader> {
		if locator.len() == 0 {
			return vec![];
		}

		// go through the locator vector and check if we know any of these headers
		let known = self.chain.get_block_header(&locator[0]);
		let header = match known {
			Ok(header) => header,
			Err(chain::Error::StoreErr(store::Error::NotFoundErr)) => {
				return self.locate_headers(locator[1..].to_vec());
			}
			Err(e) => {
				error!(LOGGER, "Could not build header locator: {:?}", e);
				return vec![];
			}
		};

		// looks like we know one, getting as many following headers as allowed
		let hh = header.height;
		let mut headers = vec![];
		for h in (hh + 1)..(hh + (p2p::MAX_BLOCK_HEADERS as u64)) {
			let header = self.chain.get_header_by_height(h);
			match header {
				Ok(head) => headers.push(head),
				Err(chain::Error::StoreErr(store::Error::NotFoundErr)) => break,
				Err(e) => {
					error!(LOGGER, "Could not build header locator: {:?}", e);
					return vec![];
				}
			}
		}
		headers
	}

	/// Gets a full block by its hash.
	fn get_block(&self, h: Hash) -> Option<core::Block> {
		let b = self.chain.get_block(&h);
		match b {
			Ok(b) => Some(b),
			_ => None,
		}
	}

	/// Find good peers we know with the provided capability and return their
	/// addresses.
	fn find_peer_addrs(&self, capab: p2p::Capabilities) -> Vec<SocketAddr> {
		let peers = self.peer_store.find_peers(
			State::Healthy,
			capab,
			p2p::MAX_PEER_ADDRS as usize,
		);
		debug!(LOGGER, "Got {} peer addrs to send.", peers.len());
		map_vec!(peers, |p| p.addr)
	}

	/// A list of peers has been received from one of our peers.
	fn peer_addrs_received(&self, peer_addrs: Vec<SocketAddr>) {
		debug!(LOGGER, "Received {} peer addrs, saving.", peer_addrs.len());
		for pa in peer_addrs {
			if let Ok(e) = self.peer_store.exists_peer(pa) {
				if e {
					continue;
				}
			}
			let peer = PeerData {
				addr: pa,
				capabilities: p2p::UNKNOWN,
				user_agent: "".to_string(),
				flags: State::Healthy,
			};
			if let Err(e) = self.peer_store.save_peer(&peer) {
				error!(LOGGER, "Could not save received peer address: {:?}", e);
			}
		}
	}

	/// Network successfully connected to a peer.
	fn peer_connected(&self, pi: &p2p::PeerInfo) {
		debug!(LOGGER, "Saving newly connected peer {}.", pi.addr);
		let peer = PeerData {
			addr: pi.addr,
			capabilities: pi.capabilities,
			user_agent: pi.user_agent.clone(),
			flags: State::Healthy,
		};
		if let Err(e) = self.peer_store.save_peer(&peer) {
			error!(LOGGER, "Could not save connected peer: {:?}", e);
		}
	}
}

impl NetToChainAdapter {
	pub fn new(
		chain_ref: Arc<chain::Chain>,
		tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
		peer_store: Arc<PeerStore>,
	) -> NetToChainAdapter {
		NetToChainAdapter {
			chain: chain_ref,
			peer_store: peer_store,
			tx_pool: tx_pool,
			syncer: OneTime::new(),
		}
	}

	/// Start syncing the chain by instantiating and running the Syncer in the
	/// background (a new thread is created).
	pub fn start_sync(&self, sync: sync::Syncer) {
		let arc_sync = Arc::new(sync);
		self.syncer.init(arc_sync.clone());
		let _ = thread::Builder::new().name("syncer".to_string()).spawn(
			move || {
				let _ = arc_sync.run();
			},
		);
	}

	pub fn syncing(&self) -> bool {
		self.syncer.is_initialized() && self.syncer.borrow().syncing()
	}

	/// Prepare options for the chain pipeline
	fn chain_opts(&self) -> chain::Options {
		let opts = if self.syncer.borrow().syncing() {
			chain::SYNC
		} else {
			chain::NONE
		};
		let param_ref = MINING_PARAMETER_MODE.read().unwrap();
		let opts = match *param_ref {
			MiningParameterMode::AutomatedTesting => opts | chain::EASY_POW,
			MiningParameterMode::UserTesting => opts | chain::EASY_POW,
			MiningParameterMode::Production => opts,
		};
		opts
	}
}

/// Implementation of the ChainAdapter for the network. Gets notified when the
/// blockchain accepted a new block, asking the pool to update its state and
/// the network to broadcast the block
pub struct ChainToPoolAndNetAdapter {
	tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
	p2p: OneTime<Arc<Server>>,
}

impl ChainAdapter for ChainToPoolAndNetAdapter {
	fn block_accepted(&self, b: &core::Block) {
		{
			if let Err(e) = self.tx_pool.write().unwrap().reconcile_block(b) {
				error!(
					LOGGER,
					"Pool could not update itself at block {}: {:?}",
					b.hash(),
					e
				);
			}
		}
		self.p2p.borrow().broadcast_block(b);
	}
}

impl ChainToPoolAndNetAdapter {
	pub fn new(
		tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
	) -> ChainToPoolAndNetAdapter {
		ChainToPoolAndNetAdapter {
			tx_pool: tx_pool,
			p2p: OneTime::new(),
		}
	}
	pub fn init(&self, p2p: Arc<Server>) {
		self.p2p.init(p2p);
	}
}

/// Implements the view of the blockchain required by the TransactionPool to
/// operate. Mostly needed to break any direct lifecycle or implementation
/// dependency between the pool and the chain.
#[derive(Clone)]
pub struct PoolToChainAdapter {
	chain: OneTime<Arc<chain::Chain>>,
}

impl PoolToChainAdapter {
	/// Create a new pool adapter
	pub fn new() -> PoolToChainAdapter {
		PoolToChainAdapter { chain: OneTime::new() }
	}

	pub fn set_chain(&self, chain_ref: Arc<chain::Chain>) {
		self.chain.init(chain_ref);
	}
}

impl pool::BlockChain for PoolToChainAdapter {
	fn get_unspent(&self, output_ref: &Commitment) -> Result<Output, pool::PoolError> {
		self.chain.borrow().get_unspent(output_ref).map_err(
			|e| match e {
				chain::types::Error::OutputNotFound => pool::PoolError::OutputNotFound,
				chain::types::Error::OutputSpent => pool::PoolError::OutputSpent,
				_ => pool::PoolError::GenericPoolError,
			},
		)
	}

	fn get_block_header_by_output_commit(
		&self,
		commit: &Commitment,
	) -> Result<BlockHeader, pool::PoolError> {
		self.chain
			.borrow()
			.get_block_header_by_output_commit(commit)
			.map_err(|_| pool::PoolError::GenericPoolError)
	}

	fn head_header(&self) -> Result<BlockHeader, pool::PoolError> {
		self.chain.borrow().head_header().map_err(|_| {
			pool::PoolError::GenericPoolError
		})
	}
}
<commit_msg>Use local ref to syncing<commit_after>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::net::SocketAddr;
use std::sync::{Arc, RwLock};
use std::thread;

use chain::{self, ChainAdapter};
use core::core::{self, Output};
use core::core::block::BlockHeader;
use core::core::hash::{Hash, Hashed};
use core::core::target::Difficulty;
use p2p::{self, NetAdapter, Server, PeerStore, PeerData, State};
use pool;
use secp::pedersen::Commitment;
use util::OneTime;
use store;
use sync;
use util::LOGGER;
use core::global::{MiningParameterMode, MINING_PARAMETER_MODE};

/// Implementation of the NetAdapter for the blockchain. Gets notified when new
/// blocks and transactions are received and forwards to the chain and pool
/// implementations.
pub struct NetToChainAdapter {
	chain: Arc<chain::Chain>,
	peer_store: Arc<PeerStore>,
	tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,

	syncer: OneTime<Arc<sync::Syncer>>,
}

impl NetAdapter for NetToChainAdapter {
	fn total_difficulty(&self) -> Difficulty {
		self.chain.total_difficulty()
	}

	fn transaction_received(&self, tx: core::Transaction) {
		let source = pool::TxSource {
			debug_name: "p2p".to_string(),
			identifier: "?.?.?.?".to_string(),
		};
		if let Err(e) = self.tx_pool.write().unwrap().add_to_memory_pool(source, tx) {
			error!(LOGGER, "Transaction rejected: {:?}", e);
		}
	}

	fn block_received(&self, b: core::Block) {
		let bhash = b.hash();
		debug!(
			LOGGER,
			"Received block {} from network, going to process.",
			bhash
		);

		// pushing the new block through the chain pipeline
		let res = self.chain.process_block(b, self.chain_opts());

		if let Err(e) = res {
			debug!(LOGGER, "Block {} refused by chain: {:?}", bhash, e);
		}

		if self.syncer.borrow().syncing() {
			self.syncer.borrow().block_received(bhash);
		}
	}

	fn headers_received(&self, bhs: Vec<core::BlockHeader>) {
		// try to add each header to our header chain
		let mut added_hs = vec![];
		for bh in bhs {
			let res = self.chain.process_block_header(&bh, self.chain_opts());
			match res {
				Ok(_) => {
					added_hs.push(bh.hash());
				}
				Err(chain::Error::Unfit(s)) => {
					info!(
						LOGGER,
						"Received unfit block header {} at {}: {}.",
						bh.hash(),
						bh.height,
						s
					);
				}
				Err(chain::Error::StoreErr(e)) => {
					error!(
						LOGGER,
						"Store error processing block header {}: {:?}",
						bh.hash(),
						e
					);
					return;
				}
				Err(e) => {
					info!(LOGGER, "Invalid block header {}: {:?}.", bh.hash(), e);
					// TODO penalize peer somehow
				}
			}
		}
		info!(
			LOGGER,
			"Added {} headers to the header chain.",
			added_hs.len()
		);

		if self.syncer.borrow().syncing() {
			self.syncer.borrow().headers_received(added_hs);
		}
	}

	fn locate_headers(&self, locator: Vec<Hash>) -> Vec<core::BlockHeader> {
		if locator.len() == 0 {
			return vec![];
		}

		// go through the locator vector and check if we know any of these headers
		let known = self.chain.get_block_header(&locator[0]);
		let header = match known {
			Ok(header) => header,
			Err(chain::Error::StoreErr(store::Error::NotFoundErr)) => {
				return self.locate_headers(locator[1..].to_vec());
			}
			Err(e) => {
				error!(LOGGER, "Could not build header locator: {:?}", e);
				return vec![];
			}
		};

		// looks like we know one, getting as many following headers as allowed
		let hh = header.height;
		let mut headers = vec![];
		for h in (hh + 1)..(hh + (p2p::MAX_BLOCK_HEADERS as u64)) {
			let header = self.chain.get_header_by_height(h);
			match header {
				Ok(head) => headers.push(head),
				Err(chain::Error::StoreErr(store::Error::NotFoundErr)) => break,
				Err(e) => {
					error!(LOGGER, "Could not build header locator: {:?}", e);
					return vec![];
				}
			}
		}
		headers
	}

	/// Gets a full block by its hash.
	fn get_block(&self, h: Hash) -> Option<core::Block> {
		let b = self.chain.get_block(&h);
		match b {
			Ok(b) => Some(b),
			_ => None,
		}
	}

	/// Find good peers we know with the provided capability and return their
	/// addresses.
	fn find_peer_addrs(&self, capab: p2p::Capabilities) -> Vec<SocketAddr> {
		let peers = self.peer_store.find_peers(
			State::Healthy,
			capab,
			p2p::MAX_PEER_ADDRS as usize,
		);
		debug!(LOGGER, "Got {} peer addrs to send.", peers.len());
		map_vec!(peers, |p| p.addr)
	}

	/// A list of peers has been received from one of our peers.
	fn peer_addrs_received(&self, peer_addrs: Vec<SocketAddr>) {
		debug!(LOGGER, "Received {} peer addrs, saving.", peer_addrs.len());
		for pa in peer_addrs {
			if let Ok(e) = self.peer_store.exists_peer(pa) {
				if e {
					continue;
				}
			}
			let peer = PeerData {
				addr: pa,
				capabilities: p2p::UNKNOWN,
				user_agent: "".to_string(),
				flags: State::Healthy,
			};
			if let Err(e) = self.peer_store.save_peer(&peer) {
				error!(LOGGER, "Could not save received peer address: {:?}", e);
			}
		}
	}

	/// Network successfully connected to a peer.
	fn peer_connected(&self, pi: &p2p::PeerInfo) {
		debug!(LOGGER, "Saving newly connected peer {}.", pi.addr);
		let peer = PeerData {
			addr: pi.addr,
			capabilities: pi.capabilities,
			user_agent: pi.user_agent.clone(),
			flags: State::Healthy,
		};
		if let Err(e) = self.peer_store.save_peer(&peer) {
			error!(LOGGER, "Could not save connected peer: {:?}", e);
		}
	}
}

impl NetToChainAdapter {
	pub fn new(
		chain_ref: Arc<chain::Chain>,
		tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
		peer_store: Arc<PeerStore>,
	) -> NetToChainAdapter {
		NetToChainAdapter {
			chain: chain_ref,
			peer_store: peer_store,
			tx_pool: tx_pool,
			syncer: OneTime::new(),
		}
	}

	/// Start syncing the chain by instantiating and running the Syncer in the
	/// background (a new thread is created).
	pub fn start_sync(&self, sync: sync::Syncer) {
		let arc_sync = Arc::new(sync);
		self.syncer.init(arc_sync.clone());
		let _ = thread::Builder::new().name("syncer".to_string()).spawn(
			move || {
				let _ = arc_sync.run();
			},
		);
	}

	pub fn syncing(&self) -> bool {
		self.syncer.is_initialized() && self.syncer.borrow().syncing()
	}

	/// Prepare options for the chain pipeline
	fn chain_opts(&self) -> chain::Options {
		let opts = if self.syncing() {
			chain::SYNC
		} else {
			chain::NONE
		};
		let param_ref = MINING_PARAMETER_MODE.read().unwrap();
		let opts = match *param_ref {
			MiningParameterMode::AutomatedTesting => opts | chain::EASY_POW,
			MiningParameterMode::UserTesting => opts | chain::EASY_POW,
			MiningParameterMode::Production => opts,
		};
		opts
	}
}

/// Implementation of the ChainAdapter for the network. Gets notified when the
/// blockchain accepted a new block, asking the pool to update its state and
/// the network to broadcast the block
pub struct ChainToPoolAndNetAdapter {
	tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
	p2p: OneTime<Arc<Server>>,
}

impl ChainAdapter for ChainToPoolAndNetAdapter {
	fn block_accepted(&self, b: &core::Block) {
		{
			if let Err(e) = self.tx_pool.write().unwrap().reconcile_block(b) {
				error!(
					LOGGER,
					"Pool could not update itself at block {}: {:?}",
					b.hash(),
					e
				);
			}
		}
		self.p2p.borrow().broadcast_block(b);
	}
}

impl ChainToPoolAndNetAdapter {
	pub fn new(
		tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
	) -> ChainToPoolAndNetAdapter {
		ChainToPoolAndNetAdapter {
			tx_pool: tx_pool,
			p2p: OneTime::new(),
		}
	}
	pub fn init(&self, p2p: Arc<Server>) {
		self.p2p.init(p2p);
	}
}

/// Implements the view of the blockchain required by the TransactionPool to
/// operate. Mostly needed to break any direct lifecycle or implementation
/// dependency between the pool and the chain.
#[derive(Clone)]
pub struct PoolToChainAdapter {
	chain: OneTime<Arc<chain::Chain>>,
}

impl PoolToChainAdapter {
	/// Create a new pool adapter
	pub fn new() -> PoolToChainAdapter {
		PoolToChainAdapter { chain: OneTime::new() }
	}

	pub fn set_chain(&self, chain_ref: Arc<chain::Chain>) {
		self.chain.init(chain_ref);
	}
}

impl pool::BlockChain for PoolToChainAdapter {
	fn get_unspent(&self, output_ref: &Commitment) -> Result<Output, pool::PoolError> {
		self.chain.borrow().get_unspent(output_ref).map_err(
			|e| match e {
				chain::types::Error::OutputNotFound => pool::PoolError::OutputNotFound,
				chain::types::Error::OutputSpent => pool::PoolError::OutputSpent,
				_ => pool::PoolError::GenericPoolError,
			},
		)
	}

	fn get_block_header_by_output_commit(
		&self,
		commit: &Commitment,
	) -> Result<BlockHeader, pool::PoolError> {
		self.chain
			.borrow()
			.get_block_header_by_output_commit(commit)
			.map_err(|_| pool::PoolError::GenericPoolError)
	}

	fn head_header(&self) -> Result<BlockHeader, pool::PoolError> {
		self.chain.borrow().head_header().map_err(|_| {
			pool::PoolError::GenericPoolError
		})
	}
}
<|endoftext|>


<commit_before>use core::{Algorithm, Predictor, Parameter, Trace};
use domains::Transition;
use fa::{Approximator, Parameterised, Projection, Projector, SimpleLFA, VFunction};
use geometry::Matrix;

pub struct TDLambda<S: ?Sized, P: Projector<S>> {
    trace: Trace,

    pub fa_theta: SimpleLFA<S, P>,

    pub alpha: Parameter,
    pub gamma: Parameter,
}

impl<S: ?Sized, P: Projector<S>> TDLambda<S, P> {
    pub fn new<T1, T2>(trace: Trace, fa_theta: SimpleLFA<S, P>, alpha: T1, gamma: T2) -> Self
    where
        T1: Into<Parameter>,
        T2: Into<Parameter>,
    {
        TDLambda {
            trace,

            fa_theta,

            alpha: alpha.into(),
            gamma: gamma.into(),
        }
    }

    #[inline(always)]
    fn update_v(&mut self, phi_s: Projection, error: f64) {
        let decay_rate = self.trace.lambda.value() * self.gamma.value();

        self.trace.decay(decay_rate);
        self.trace
            .update(&phi_s.expanded(self.fa_theta.projector.dim()));

        self.fa_theta
            .update_phi(&Projection::Dense(self.trace.get()), self.alpha * error);
    }
}

impl<S, A, M: Projector<S>> Algorithm<S, A> for TDLambda<S, M>
where
    Self: Predictor<S, A>
{
    fn handle_sample(&mut self, t: &Transition<S, A>) {
        let phi_s = self.fa_theta.projector.project(&t.from.state());

        let v = self.fa_theta.evaluate_phi(&phi_s);
        let nv = self.predict_v(t.to.state());

        let td_error = t.reward + self.gamma * nv - v;

        self.update_v(phi_s, td_error)
    }

    fn handle_terminal(&mut self, t: &Transition<S, A>) {
        {
            let phi_s = self.fa_theta.projector.project(&t.from.state());
            let td_error = t.reward - self.fa_theta.evaluate_phi(&phi_s);

            self.update_v(phi_s, td_error);

            self.trace.decay(0.0);
        }

        self.alpha = self.alpha.step();
        self.gamma = self.gamma.step();
    }
}

impl<S, A, P: Projector<S>> Predictor<S, A> for TDLambda<S, P> {
    fn predict_v(&mut self, s: &S) -> f64 { self.fa_theta.evaluate(s).unwrap() }
}

impl<S, P: Projector<S>> Parameterised for TDLambda<S, P> {
    fn weights(&self) -> Matrix<f64> {
        self.fa_theta.weights()
    }
}
<commit_msg>style(prediction): move TDLambda trace member to end of definition<commit_after>use core::{Algorithm, Predictor, Parameter, Trace};
use domains::Transition;
use fa::{Approximator, Parameterised, Projection, Projector, SimpleLFA, VFunction};
use geometry::Matrix;

pub struct TDLambda<S: ?Sized, P: Projector<S>> {
    pub fa_theta: SimpleLFA<S, P>,

    pub alpha: Parameter,
    pub gamma: Parameter,

    trace: Trace,
}

impl<S: ?Sized, P: Projector<S>> TDLambda<S, P> {
    pub fn new<T1, T2>(trace: Trace, fa_theta: SimpleLFA<S, P>, alpha: T1, gamma: T2) -> Self
    where
        T1: Into<Parameter>,
        T2: Into<Parameter>,
    {
        TDLambda {
            fa_theta,

            alpha: alpha.into(),
            gamma: gamma.into(),

            trace,
        }
    }

    #[inline(always)]
    fn update_v(&mut self, phi_s: Projection, error: f64) {
        let decay_rate = self.trace.lambda.value() * self.gamma.value();

        self.trace.decay(decay_rate);
        self.trace
            .update(&phi_s.expanded(self.fa_theta.projector.dim()));

        self.fa_theta
            .update_phi(&Projection::Dense(self.trace.get()), self.alpha * error);
    }
}

impl<S, A, M: Projector<S>> Algorithm<S, A> for TDLambda<S, M>
where
    Self: Predictor<S, A>
{
    fn handle_sample(&mut self, t: &Transition<S, A>) {
        let phi_s = self.fa_theta.projector.project(&t.from.state());

        let v = self.fa_theta.evaluate_phi(&phi_s);
        let nv = self.predict_v(t.to.state());

        let td_error = t.reward + self.gamma * nv - v;

        self.update_v(phi_s, td_error)
    }

    fn handle_terminal(&mut self, t: &Transition<S, A>) {
        {
            let phi_s = self.fa_theta.projector.project(&t.from.state());
            let td_error = t.reward - self.fa_theta.evaluate_phi(&phi_s);

            self.update_v(phi_s, td_error);

            self.trace.decay(0.0);
        }

        self.alpha = self.alpha.step();
        self.gamma = self.gamma.step();
    }
}

impl<S, A, P: Projector<S>> Predictor<S, A> for TDLambda<S, P> {
    fn predict_v(&mut self, s: &S) -> f64 { self.fa_theta.evaluate(s).unwrap() }
}

impl<S, P: Projector<S>> Parameterised for TDLambda<S, P> {
    fn weights(&self) -> Matrix<f64> {
        self.fa_theta.weights()
    }
}
<|endoftext|>


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

// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::sync::mpsc::channel;
use std::os;
use std::str::from_str;
use std::thread::Thread;
use std::uint;

// This is a simple bench that creates M pairs of tasks. These
// tasks ping-pong back and forth over a pair of streams. This is a
// canonical message-passing benchmark as it heavily strains message
// passing and almost nothing else.

fn ping_pong_bench(n: uint, m: uint) {

    // Create pairs of tasks that pingpong back and forth.
    fn run_pair(n: uint) {
        // Create a stream A->B
        let (atx, arx) = channel::<()>();
        // Create a stream B->A
        let (btx, brx) = channel::<()>();

        Thread::spawn(move|| {
            let (tx, rx) = (atx, brx);
            for _ in range(0, n) {
                tx.send(());
                rx.recv();
            }
        }).detach();

        Thread::spawn(move|| {
            let (tx, rx) = (btx, arx);
            for _ in range(0, n) {
                rx.recv();
                tx.send(());
            }
        }).detach();
    }

    for _ in range(0, m) {
        run_pair(n)
    }
}

fn main() {

    let args = os::args();
    let args = args.as_slice();
    let n = if args.len() == 3 {
        from_str::<uint>(args[1].as_slice()).unwrap()
    } else {
        10000
    };

    let m = if args.len() == 3 {
        from_str::<uint>(args[2].as_slice()).unwrap()
    } else {
        4
    };

    ping_pong_bench(n, m);

}
<commit_msg>bench: remove warnings from rt-messaging-ping-pong.rs<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::sync::mpsc::channel;
use std::os;
use std::thread::Thread;

// This is a simple bench that creates M pairs of tasks. These
// tasks ping-pong back and forth over a pair of streams. This is a
// canonical message-passing benchmark as it heavily strains message
// passing and almost nothing else.

fn ping_pong_bench(n: uint, m: uint) {

    // Create pairs of tasks that pingpong back and forth.
    fn run_pair(n: uint) {
        // Create a channel: A->B
        let (atx, arx) = channel();
        // Create a channel: B->A
        let (btx, brx) = channel();

        Thread::spawn(move|| {
            let (tx, rx) = (atx, brx);
            for _ in range(0, n) {
                tx.send(()).unwrap();
                rx.recv().unwrap();
            }
        }).detach();

        Thread::spawn(move|| {
            let (tx, rx) = (btx, arx);
            for _ in range(0, n) {
                rx.recv().unwrap();
                tx.send(()).unwrap();
            }
        }).detach();
    }

    for _ in range(0, m) {
        run_pair(n)
    }
}

fn main() {

    let args = os::args();
    let args = args.as_slice();
    let n = if args.len() == 3 {
        args[1].parse::<uint>().unwrap()
    } else {
        10000
    };

    let m = if args.len() == 3 {
        args[2].parse::<uint>().unwrap()
    } else {
        4
    };

    ping_pong_bench(n, m);

}
<|endoftext|>


<commit_before>// run-pass
// ignore-windows - this is a unix-specific test
// ignore-cloudabi
// ignore-emscripten
// ignore-sgx
// ignore-musl - returns dummy result for _SC_NGROUPS_MAX

#![feature(rustc_private)]
#![feature(setgroups)]

extern crate libc;
use std::process::Command;
use std::os::unix::process::CommandExt;

fn main() {
    #[cfg(unix)]
    run()
}

#[cfg(unix)]
fn run() {
    let max_ngroups = unsafe { libc::sysconf(libc::_SC_NGROUPS_MAX) };
    let max_ngroups = max_ngroups as u32 + 1;
    let vec: Vec<u32> = (0..max_ngroups).collect();
    let p = Command::new("/bin/id").groups(&vec[..]).spawn();
    assert!(p.is_err());
}
<commit_msg>Auto merge of #83602 - JohnTitor:cloudabi-flag-is-unnecessary, r=Xanewok<commit_after>// run-pass
// ignore-windows - this is a unix-specific test
// ignore-emscripten
// ignore-sgx
// ignore-musl - returns dummy result for _SC_NGROUPS_MAX

#![feature(rustc_private)]
#![feature(setgroups)]

extern crate libc;
use std::process::Command;
use std::os::unix::process::CommandExt;

fn main() {
    #[cfg(unix)]
    run()
}

#[cfg(unix)]
fn run() {
    let max_ngroups = unsafe { libc::sysconf(libc::_SC_NGROUPS_MAX) };
    let max_ngroups = max_ngroups as u32 + 1;
    let vec: Vec<u32> = (0..max_ngroups).collect();
    let p = Command::new("/bin/id").groups(&vec[..]).spawn();
    assert!(p.is_err());
}
<|endoftext|>


<commit_before>// run-pass
#![feature(const_discriminant)]

use std::mem::{discriminant, Discriminant};

fn identity<T>(x: T) -> T { x }

enum Test {
    A(u8),
    B,
    C { a: u8, b: u8 },
}

const TEST_A: Discriminant<Test> = discriminant(&Test::A(5));
const TEST_A_OTHER: Discriminant<Test> = discriminant(&Test::A(17));
const TEST_B: Discriminant<Test> = discriminant(&Test::B);

enum Void {}

enum SingleVariant {
    V,
    Never(Void),
}

const TEST_V: Discriminant<SingleVariant> = discriminant(&SingleVariant::V);

fn main() {
    assert_eq!(TEST_A, TEST_A_OTHER);
    assert_eq!(TEST_A, discriminant(identity(&Test::A(17))));
    assert_eq!(TEST_B, discriminant(identity(&Test::B)));
    assert_ne!(TEST_A, TEST_B);
    assert_ne!(TEST_B, discriminant(identity(&Test::C { a: 42, b: 7 })));

    assert_eq!(TEST_V, discriminant(identity(&SingleVariant::V)));
}
<commit_msg>allow dead code in discriminant test<commit_after>// run-pass
#![feature(const_discriminant)]
#![allow(dead_code)]

use std::mem::{discriminant, Discriminant};

fn identity<T>(x: T) -> T { x }

enum Test {
    A(u8),
    B,
    C { a: u8, b: u8 },
}

const TEST_A: Discriminant<Test> = discriminant(&Test::A(5));
const TEST_A_OTHER: Discriminant<Test> = discriminant(&Test::A(17));
const TEST_B: Discriminant<Test> = discriminant(&Test::B);

enum Void {}

enum SingleVariant {
    V,
    Never(Void),
}

const TEST_V: Discriminant<SingleVariant> = discriminant(&SingleVariant::V);

fn main() {
    assert_eq!(TEST_A, TEST_A_OTHER);
    assert_eq!(TEST_A, discriminant(identity(&Test::A(17))));
    assert_eq!(TEST_B, discriminant(identity(&Test::B)));
    assert_ne!(TEST_A, TEST_B);
    assert_ne!(TEST_B, discriminant(identity(&Test::C { a: 42, b: 7 })));

    assert_eq!(TEST_V, discriminant(identity(&SingleVariant::V)));
}
<|endoftext|>