<commit_before>//! Defines the metrics system.
//! The main design goals of this system are:
//! - Use lockless operations, preferably ones that don't require anything other than
//!   simple reads/writes being atomic.
//! - Exploit interior mutability and atomics being Sync to allow all methods (including the ones
//!   which are effectively mutable) to be callable on a global non-mut static.
//! - Rely on Serde to provide the actual serialization for logging the metrics.
//! - Since all metrics start at 0, we implement the Default trait via derive for all of them,
//!   to avoid having to initialize everything by hand.

//! Moreover, the value of a metric is currently NOT reset to 0 each time it's being logged. The
//! current approach is to store two values (current and previous) and compute the delta between
//! them each time we do a flush (i.e by serialization). There are a number of advantages
//! to this approach, including:
//! - We don't have to introduce an additional write (to reset the value) from the thread which
//!   does to actual logging, so less synchronization effort is required.
//! - We don't have to worry at all that much about losing some data if logging fails for a while
//!   (this could be a concern, I guess).
//!
//! If if turns out this approach is not really what we want, it's pretty easy to resort to
//! something else, while working behind the same interface.

use std::sync::atomic::{AtomicUsize, Ordering};

use chrono;
use serde::{Serialize, Serializer};

const SYSCALL_MAX: usize = 350;

/// Used for defining new types of metrics that can be either incremented with an unit
/// or an arbitrary amount of units.
// This trait helps with writing less code. It has to be in scope (via an use directive) in order
// for its methods to be available to call on structs that implement it.
pub trait Metric {
    fn add(&self, value: usize);
    fn inc(&self) {
        self.add(1);
    }
    fn count(&self) -> usize;
}

// A simple metric is one meant to be incremented from a single thread, so it can use simple
// loads + stores. Loads are currently Relaxed everywhere, because we don't do anything besides
// logging the retrieved value (their outcome os not used to modify some memory location in a
// potentially inconsistent manner). There's no way currently to make sure a SimpleMetric is only
// incremented by a single thread, this has to be enforced via judicious use (although, every
// non-vCPU related metric is associated with a particular thread, so it shouldn't be that easy
// to misuse SimpleMetric fields).
#[derive(Default)]
pub struct SimpleMetric(AtomicUsize);

impl Metric for SimpleMetric {
    fn add(&self, value: usize) {
        let ref count = self.0;
        count.store(count.load(Ordering::Relaxed) + value, Ordering::Relaxed);
    }

    fn count(&self) -> usize {
        self.0.load(Ordering::Relaxed)
    }
}

impl Serialize for SimpleMetric {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        // There's no serializer.serialize_usize() for some reason :(
        serializer.serialize_u64(self.0.load(Ordering::Relaxed) as u64)
    }
}

// A shared metric is one which is expected to be incremented from more than one thread, so more
// synchronization is necessary. It's currently used for vCPU metrics. An alternative here would be
// to have one instance of every metric for each thread (like a per-thread SimpleMetric), and to
// aggregate them when logging. However this probably overkill unless we have a lot of vCPUs
// incrementing metrics very often. Still, it's there if we ever need it :-s
#[derive(Default)]
// We will be keeping two values for each metric for being able to reset
// counters on each metric.
// 1st member - current value being updated
// 2nd member - old value that gets the current value whenever metrics is flushed to disk
pub struct SharedMetric(AtomicUsize, AtomicUsize);

impl Metric for SharedMetric {
    // While the order specified for this operation is still Relaxed, the actual instruction will
    // be an asm "LOCK; something" and thus atomic across multiple threads, simply because of the
    // fetch_and_add (as opposed to "store(load() + 1)") implementation for atomics.
    // TODO: would a stronger ordering make a difference here?
    fn add(&self, value: usize) {
        self.0.fetch_add(value, Ordering::Relaxed);
    }

    fn count(&self) -> usize {
        self.0.load(Ordering::Relaxed)
    }
}

impl Serialize for SharedMetric {
    /// Reset counters of each metrics. Here we suppose that Serialize's goal is to help with the
    /// flushing of metrics.
    /// !!! Any print of the metrics will also reset them. Use with caution !!!
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        // There's no serializer.serialize_usize() for some reason :(
        let snapshot = self.0.load(Ordering::Relaxed);
        let res = serializer.serialize_u64(snapshot as u64 - self.1.load(Ordering::Relaxed) as u64);

        if res.is_ok() {
            self.1.store(snapshot, Ordering::Relaxed);
        }
        res
    }
}

// The following structs are used to define a certain organization for the set of metrics we
// are interested in. Whenever the name of a field differs from its ideal textual representation
// in the serialized form, we can use the #[serde(rename = "name")] attribute to, well, rename it.

// Metrics related to the internal api server
#[derive(Default, Serialize)]
pub struct ApiServerMetrics {
    pub async_missed_actions_count: SharedMetric,
    pub async_outcome_fails: SharedMetric,
    pub async_vmm_send_timeout_count: SharedMetric,
    pub instance_info_fails: SharedMetric,
    pub sync_outcome_fails: SharedMetric,
    pub sync_vmm_send_timeout_count: SharedMetric,
}

// Metrics on GET Api Requests
#[derive(Default, Serialize)]
pub struct GetRequestsMetrics {
    pub action_info_count: SharedMetric,
    pub actions_count: SharedMetric,
    pub actions_fails: SharedMetric,
    pub instance_info_count: SharedMetric,
    pub machine_cfg_count: SharedMetric,
    pub machine_cfg_fails: SharedMetric,
}

// Metrics on PUT Api Requests
#[derive(Default, Serialize)]
pub struct PutRequestsMetrics {
    pub actions_count: SharedMetric,
    pub actions_fails: SharedMetric,
    pub boot_source_count: SharedMetric,
    pub boot_source_fails: SharedMetric,
    pub drive_fails: SharedMetric,
    pub drive_count: SharedMetric,
    pub logger_count: SharedMetric,
    pub logger_fails: SharedMetric,
    pub machine_cfg_count: SharedMetric,
    pub machine_cfg_fails: SharedMetric,
    pub network_count: SharedMetric,
    pub network_fails: SharedMetric,
}

#[derive(Default, Serialize)]
pub struct BlockDeviceMetrics {
    pub activate_fails: SharedMetric,
    pub cfg_fails: SharedMetric,
    pub event_fails: SharedMetric,
    pub execute_fails: SharedMetric,
    pub invalid_reqs_count: SharedMetric,
    pub flush_count: SharedMetric,
    pub queue_event_count: SharedMetric,
    pub rate_limiter_event_count: SharedMetric,
    pub read_count: SharedMetric,
    pub write_count: SharedMetric,
}

#[derive(Default, Serialize)]
pub struct I8042DeviceMetrics {
    pub error_count: SharedMetric,
    pub missed_read_count: SharedMetric,
    pub missed_write_count: SharedMetric,
    pub read_count: SharedMetric,
    pub reset_count: SharedMetric,
    pub write_count: SharedMetric,
}

#[derive(Default, Serialize)]
pub struct LoggerSystemMetrics {
    pub missed_metrics_count: SharedMetric,
    pub metrics_fails: SharedMetric,
    pub missed_log_count: SharedMetric,
    pub log_fails: SharedMetric,
}

#[derive(Default, Serialize)]
pub struct NetDeviceMetrics {
    pub activate_fails: SharedMetric,
    pub cfg_fails: SharedMetric,
    pub event_fails: SharedMetric,
    pub rx_queue_event_count: SharedMetric,
    pub rx_event_rate_limiter_count: SharedMetric,
    pub rx_tap_event_count: SharedMetric,
    pub rx_bytes_count: SharedMetric,
    pub rx_packets_count: SharedMetric,
    pub rx_fails: SharedMetric,
    pub tx_queue_event_count: SharedMetric,
    pub tx_rate_limiter_event_count: SharedMetric,
    pub tx_bytes_count: SharedMetric,
    pub tx_packets_count: SharedMetric,
    pub tx_fails: SharedMetric,
}

#[derive(Serialize)]
pub struct SeccompMetrics {
    pub num_faults: SharedMetric,
    pub bad_syscalls: Vec<SharedMetric>,
}

impl Default for SeccompMetrics {
    fn default() -> SeccompMetrics {
        let mut def_syscalls = vec![];
        for _syscall in 0..SYSCALL_MAX {
            def_syscalls.push(SharedMetric::default());
        }
        SeccompMetrics {
            num_faults: SharedMetric::default(),
            bad_syscalls: def_syscalls,
        }
    }
}

#[derive(Default, Serialize)]
pub struct SerialDeviceMetrics {
    pub error_count: SharedMetric,
    pub flush_count: SharedMetric,
    pub missed_read_count: SharedMetric,
    pub missed_write_count: SharedMetric,
    pub read_count: SharedMetric,
    pub write_count: SharedMetric,
}

#[derive(Default, Serialize)]
pub struct VcpuMetrics {
    pub eagain: SharedMetric,
    pub eintr: SharedMetric,
    pub exit_io_in: SharedMetric,
    pub exit_io_out: SharedMetric,
    pub exit_mmio_read: SharedMetric,
    pub exit_mmio_write: SharedMetric,
    pub failures: SharedMetric,
}

#[derive(Default, Serialize)]
pub struct VmmMetrics {
    pub device_events: SharedMetric,
}

// The sole purpose of this struct is to produce an UTC timestamp when an instance is serialized.
#[derive(Default)]
struct SerializeToUtcTimestampMs;

impl Serialize for SerializeToUtcTimestampMs {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_i64(chrono::Utc::now().timestamp_millis())
    }
}

#[derive(Default, Serialize)]
pub struct FirecrackerMetrics {
    utc_timestamp_ms: SerializeToUtcTimestampMs,
    pub api_server: ApiServerMetrics,
    pub block: BlockDeviceMetrics,
    pub get_api_requests: GetRequestsMetrics,
    pub i8042: I8042DeviceMetrics,
    pub logger: LoggerSystemMetrics,
    pub net: NetDeviceMetrics,
    pub put_api_requests: PutRequestsMetrics,
    pub seccomp: SeccompMetrics,
    pub vcpu: VcpuMetrics,
    pub vmm: VmmMetrics,
    pub uart: SerialDeviceMetrics,
}

lazy_static! {
    /// Static instance used for handling metrics.
    ///
    pub static ref METRICS: FirecrackerMetrics = FirecrackerMetrics::default();
}

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

    use std::sync::Arc;
    use std::thread;

    #[test]
    fn test_metric() {
        let m1 = SimpleMetric::default();

        m1.inc();
        m1.inc();
        m1.add(5);
        m1.inc();

        assert_eq!(m1.count(), 8);

        let m2 = Arc::new(SharedMetric::default());

        // We're going to create a number of threads that will attempt to increase this metric
        // in parallel. If everything goes fine we still can't be sure the synchronization works,
        // but it something fails, then we definitely have a problem :-s

        const NUM_THREADS_TO_SPAWN: usize = 4;
        const NUM_INCREMENTS_PER_THREAD: usize = 100000;
        const M2_INITIAL_COUNT: usize = 123;

        m2.add(M2_INITIAL_COUNT);

        let mut v = Vec::with_capacity(NUM_THREADS_TO_SPAWN);

        for _ in 0..NUM_THREADS_TO_SPAWN {
            let r = m2.clone();
            v.push(thread::spawn(move || {
                for _ in 0..NUM_INCREMENTS_PER_THREAD {
                    r.inc();
                }
            }));
        }

        for handle in v {
            handle.join().unwrap();
        }

        assert_eq!(
            m2.count(),
            M2_INITIAL_COUNT + NUM_THREADS_TO_SPAWN * NUM_INCREMENTS_PER_THREAD
        );
    }

    #[test]
    fn test_serialize() {
        let s = serde_json::to_string(&FirecrackerMetrics::default());
        assert!(s.is_ok());
    }
}
<commit_msg>Add metrics for PATCH /drives<commit_after>//! Defines the metrics system.
//! The main design goals of this system are:
//! - Use lockless operations, preferably ones that don't require anything other than
//!   simple reads/writes being atomic.
//! - Exploit interior mutability and atomics being Sync to allow all methods (including the ones
//!   which are effectively mutable) to be callable on a global non-mut static.
//! - Rely on Serde to provide the actual serialization for logging the metrics.
//! - Since all metrics start at 0, we implement the Default trait via derive for all of them,
//!   to avoid having to initialize everything by hand.

//! Moreover, the value of a metric is currently NOT reset to 0 each time it's being logged. The
//! current approach is to store two values (current and previous) and compute the delta between
//! them each time we do a flush (i.e by serialization). There are a number of advantages
//! to this approach, including:
//! - We don't have to introduce an additional write (to reset the value) from the thread which
//!   does to actual logging, so less synchronization effort is required.
//! - We don't have to worry at all that much about losing some data if logging fails for a while
//!   (this could be a concern, I guess).
//!
//! If if turns out this approach is not really what we want, it's pretty easy to resort to
//! something else, while working behind the same interface.

use std::sync::atomic::{AtomicUsize, Ordering};

use chrono;
use serde::{Serialize, Serializer};

const SYSCALL_MAX: usize = 350;

/// Used for defining new types of metrics that can be either incremented with an unit
/// or an arbitrary amount of units.
// This trait helps with writing less code. It has to be in scope (via an use directive) in order
// for its methods to be available to call on structs that implement it.
pub trait Metric {
    fn add(&self, value: usize);
    fn inc(&self) {
        self.add(1);
    }
    fn count(&self) -> usize;
}

// A simple metric is one meant to be incremented from a single thread, so it can use simple
// loads + stores. Loads are currently Relaxed everywhere, because we don't do anything besides
// logging the retrieved value (their outcome os not used to modify some memory location in a
// potentially inconsistent manner). There's no way currently to make sure a SimpleMetric is only
// incremented by a single thread, this has to be enforced via judicious use (although, every
// non-vCPU related metric is associated with a particular thread, so it shouldn't be that easy
// to misuse SimpleMetric fields).
#[derive(Default)]
pub struct SimpleMetric(AtomicUsize);

impl Metric for SimpleMetric {
    fn add(&self, value: usize) {
        let ref count = self.0;
        count.store(count.load(Ordering::Relaxed) + value, Ordering::Relaxed);
    }

    fn count(&self) -> usize {
        self.0.load(Ordering::Relaxed)
    }
}

impl Serialize for SimpleMetric {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        // There's no serializer.serialize_usize() for some reason :(
        serializer.serialize_u64(self.0.load(Ordering::Relaxed) as u64)
    }
}

// A shared metric is one which is expected to be incremented from more than one thread, so more
// synchronization is necessary. It's currently used for vCPU metrics. An alternative here would be
// to have one instance of every metric for each thread (like a per-thread SimpleMetric), and to
// aggregate them when logging. However this probably overkill unless we have a lot of vCPUs
// incrementing metrics very often. Still, it's there if we ever need it :-s
#[derive(Default)]
// We will be keeping two values for each metric for being able to reset
// counters on each metric.
// 1st member - current value being updated
// 2nd member - old value that gets the current value whenever metrics is flushed to disk
pub struct SharedMetric(AtomicUsize, AtomicUsize);

impl Metric for SharedMetric {
    // While the order specified for this operation is still Relaxed, the actual instruction will
    // be an asm "LOCK; something" and thus atomic across multiple threads, simply because of the
    // fetch_and_add (as opposed to "store(load() + 1)") implementation for atomics.
    // TODO: would a stronger ordering make a difference here?
    fn add(&self, value: usize) {
        self.0.fetch_add(value, Ordering::Relaxed);
    }

    fn count(&self) -> usize {
        self.0.load(Ordering::Relaxed)
    }
}

impl Serialize for SharedMetric {
    /// Reset counters of each metrics. Here we suppose that Serialize's goal is to help with the
    /// flushing of metrics.
    /// !!! Any print of the metrics will also reset them. Use with caution !!!
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        // There's no serializer.serialize_usize() for some reason :(
        let snapshot = self.0.load(Ordering::Relaxed);
        let res = serializer.serialize_u64(snapshot as u64 - self.1.load(Ordering::Relaxed) as u64);

        if res.is_ok() {
            self.1.store(snapshot, Ordering::Relaxed);
        }
        res
    }
}

// The following structs are used to define a certain organization for the set of metrics we
// are interested in. Whenever the name of a field differs from its ideal textual representation
// in the serialized form, we can use the #[serde(rename = "name")] attribute to, well, rename it.

// Metrics related to the internal api server
#[derive(Default, Serialize)]
pub struct ApiServerMetrics {
    pub async_missed_actions_count: SharedMetric,
    pub async_outcome_fails: SharedMetric,
    pub async_vmm_send_timeout_count: SharedMetric,
    pub instance_info_fails: SharedMetric,
    pub sync_outcome_fails: SharedMetric,
    pub sync_vmm_send_timeout_count: SharedMetric,
}

// Metrics on GET Api Requests
#[derive(Default, Serialize)]
pub struct GetRequestsMetrics {
    pub action_info_count: SharedMetric,
    pub actions_count: SharedMetric,
    pub actions_fails: SharedMetric,
    pub instance_info_count: SharedMetric,
    pub machine_cfg_count: SharedMetric,
    pub machine_cfg_fails: SharedMetric,
}

// Metrics on PUT Api Requests
#[derive(Default, Serialize)]
pub struct PutRequestsMetrics {
    pub actions_count: SharedMetric,
    pub actions_fails: SharedMetric,
    pub boot_source_count: SharedMetric,
    pub boot_source_fails: SharedMetric,
    pub drive_fails: SharedMetric,
    pub drive_count: SharedMetric,
    pub logger_count: SharedMetric,
    pub logger_fails: SharedMetric,
    pub machine_cfg_count: SharedMetric,
    pub machine_cfg_fails: SharedMetric,
    pub network_count: SharedMetric,
    pub network_fails: SharedMetric,
}

// Metrics on PATCH Api Requests
#[derive(Default, Serialize)]
pub struct PatchRequestsMetrics {
    pub drive_fails: SharedMetric,
    pub drive_count: SharedMetric,
}

#[derive(Default, Serialize)]
pub struct BlockDeviceMetrics {
    pub activate_fails: SharedMetric,
    pub cfg_fails: SharedMetric,
    pub event_fails: SharedMetric,
    pub execute_fails: SharedMetric,
    pub invalid_reqs_count: SharedMetric,
    pub flush_count: SharedMetric,
    pub queue_event_count: SharedMetric,
    pub rate_limiter_event_count: SharedMetric,
    pub update_count: SharedMetric,
    pub update_fails: SharedMetric,
    pub read_count: SharedMetric,
    pub write_count: SharedMetric,
}

#[derive(Default, Serialize)]
pub struct I8042DeviceMetrics {
    pub error_count: SharedMetric,
    pub missed_read_count: SharedMetric,
    pub missed_write_count: SharedMetric,
    pub read_count: SharedMetric,
    pub reset_count: SharedMetric,
    pub write_count: SharedMetric,
}

#[derive(Default, Serialize)]
pub struct LoggerSystemMetrics {
    pub missed_metrics_count: SharedMetric,
    pub metrics_fails: SharedMetric,
    pub missed_log_count: SharedMetric,
    pub log_fails: SharedMetric,
}

#[derive(Default, Serialize)]
pub struct NetDeviceMetrics {
    pub activate_fails: SharedMetric,
    pub cfg_fails: SharedMetric,
    pub event_fails: SharedMetric,
    pub rx_queue_event_count: SharedMetric,
    pub rx_event_rate_limiter_count: SharedMetric,
    pub rx_tap_event_count: SharedMetric,
    pub rx_bytes_count: SharedMetric,
    pub rx_packets_count: SharedMetric,
    pub rx_fails: SharedMetric,
    pub tx_queue_event_count: SharedMetric,
    pub tx_rate_limiter_event_count: SharedMetric,
    pub tx_bytes_count: SharedMetric,
    pub tx_packets_count: SharedMetric,
    pub tx_fails: SharedMetric,
}

#[derive(Serialize)]
pub struct SeccompMetrics {
    pub num_faults: SharedMetric,
    pub bad_syscalls: Vec<SharedMetric>,
}

impl Default for SeccompMetrics {
    fn default() -> SeccompMetrics {
        let mut def_syscalls = vec![];
        for _syscall in 0..SYSCALL_MAX {
            def_syscalls.push(SharedMetric::default());
        }
        SeccompMetrics {
            num_faults: SharedMetric::default(),
            bad_syscalls: def_syscalls,
        }
    }
}

#[derive(Default, Serialize)]
pub struct SerialDeviceMetrics {
    pub error_count: SharedMetric,
    pub flush_count: SharedMetric,
    pub missed_read_count: SharedMetric,
    pub missed_write_count: SharedMetric,
    pub read_count: SharedMetric,
    pub write_count: SharedMetric,
}

#[derive(Default, Serialize)]
pub struct VcpuMetrics {
    pub eagain: SharedMetric,
    pub eintr: SharedMetric,
    pub exit_io_in: SharedMetric,
    pub exit_io_out: SharedMetric,
    pub exit_mmio_read: SharedMetric,
    pub exit_mmio_write: SharedMetric,
    pub failures: SharedMetric,
}

#[derive(Default, Serialize)]
pub struct VmmMetrics {
    pub device_events: SharedMetric,
}

// The sole purpose of this struct is to produce an UTC timestamp when an instance is serialized.
#[derive(Default)]
struct SerializeToUtcTimestampMs;

impl Serialize for SerializeToUtcTimestampMs {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_i64(chrono::Utc::now().timestamp_millis())
    }
}

#[derive(Default, Serialize)]
pub struct FirecrackerMetrics {
    utc_timestamp_ms: SerializeToUtcTimestampMs,
    pub api_server: ApiServerMetrics,
    pub block: BlockDeviceMetrics,
    pub get_api_requests: GetRequestsMetrics,
    pub i8042: I8042DeviceMetrics,
    pub logger: LoggerSystemMetrics,
    pub net: NetDeviceMetrics,
    pub patch_api_requests: PatchRequestsMetrics,
    pub put_api_requests: PutRequestsMetrics,
    pub seccomp: SeccompMetrics,
    pub vcpu: VcpuMetrics,
    pub vmm: VmmMetrics,
    pub uart: SerialDeviceMetrics,
}

lazy_static! {
    /// Static instance used for handling metrics.
    ///
    pub static ref METRICS: FirecrackerMetrics = FirecrackerMetrics::default();
}

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

    use std::sync::Arc;
    use std::thread;

    #[test]
    fn test_metric() {
        let m1 = SimpleMetric::default();

        m1.inc();
        m1.inc();
        m1.add(5);
        m1.inc();

        assert_eq!(m1.count(), 8);

        let m2 = Arc::new(SharedMetric::default());

        // We're going to create a number of threads that will attempt to increase this metric
        // in parallel. If everything goes fine we still can't be sure the synchronization works,
        // but it something fails, then we definitely have a problem :-s

        const NUM_THREADS_TO_SPAWN: usize = 4;
        const NUM_INCREMENTS_PER_THREAD: usize = 100000;
        const M2_INITIAL_COUNT: usize = 123;

        m2.add(M2_INITIAL_COUNT);

        let mut v = Vec::with_capacity(NUM_THREADS_TO_SPAWN);

        for _ in 0..NUM_THREADS_TO_SPAWN {
            let r = m2.clone();
            v.push(thread::spawn(move || {
                for _ in 0..NUM_INCREMENTS_PER_THREAD {
                    r.inc();
                }
            }));
        }

        for handle in v {
            handle.join().unwrap();
        }

        assert_eq!(
            m2.count(),
            M2_INITIAL_COUNT + NUM_THREADS_TO_SPAWN * NUM_INCREMENTS_PER_THREAD
        );
    }

    #[test]
    fn test_serialize() {
        let s = serde_json::to_string(&FirecrackerMetrics::default());
        assert!(s.is_ok());
    }
}
<|endoftext|>


<commit_before>use cssparser::Parser;

use crate::coord_units::CoordUnits;
use crate::drawing_ctx::{DrawingCtx, ViewParams};
use crate::error::*;
use crate::filter::Filter;
use crate::filters::{
    gaussian_blur::GaussianBlur, FilterResolveError, FilterSpec, Primitive, PrimitiveParams,
    ResolvedPrimitive,
};
use crate::length::*;
use crate::parsers::Parse;
use crate::properties::ComputedValues;

/// CSS Filter functions from the Filter Effects Module Level 1
///
/// https://www.w3.org/TR/filter-effects/#filter-functions
#[derive(Debug, Clone, PartialEq)]
pub enum FilterFunction {
    Blur(Blur),
}

/// Parameters for the `blur()` filter function
///
/// https://www.w3.org/TR/filter-effects/#funcdef-filter-blur
#[derive(Debug, Clone, PartialEq)]
pub struct Blur {
    std_deviation: Option<Length<Both>>,
}

fn parse_function<'i, F>(
    parser: &mut Parser<'i, '_>,
    name: &str,
    f: F,
) -> Result<FilterFunction, ParseError<'i>>
where
    F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result<FilterFunction, ParseError<'i>>,
{
    parser.expect_function_matching(name)?;
    parser.parse_nested_block(f)
}

fn parse_blur<'i>(parser: &mut Parser<'i, '_>) -> Result<FilterFunction, ParseError<'i>> {
    let length = if let Ok(length) = parser.try_parse(|p| Length::parse(p)) {
        Some(length)
    } else {
        None
    };

    Ok(FilterFunction::Blur(Blur {
        std_deviation: length,
    }))
}

impl Blur {
    fn to_filter_spec(
        &self,
        values: &ComputedValues,
        params: &ViewParams,
    ) -> Result<FilterSpec, FilterResolveError> {
        // The 0.0 default is from the spec
        let std_dev = self
            .std_deviation
            .map(|l| l.normalize(values, params))
            .unwrap_or(0.0);

        let user_space_filter = Filter::default().to_user_space(values, params);

        let gaussian_blur = ResolvedPrimitive {
            primitive: Primitive::default(),
            params: PrimitiveParams::GaussianBlur(GaussianBlur {
                std_deviation: (std_dev, std_dev),
                ..GaussianBlur::default()
            }),
        }
        .into_user_space(values, params);

        Ok(FilterSpec {
            user_space_filter,
            primitives: vec![gaussian_blur],
        })
    }
}

impl Parse for FilterFunction {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, crate::error::ParseError<'i>> {
        let loc = parser.current_source_location();

        parser
            .try_parse(|p| parse_function(p, "blur", parse_blur))
            .or_else(|_| {
                Err(loc.new_custom_error(ValueErrorKind::parse_error("expected filter function")))
            })
    }
}

impl FilterFunction {
    pub fn to_filter_spec(
        &self,
        values: &ComputedValues,
        draw_ctx: &DrawingCtx,
    ) -> Result<FilterSpec, FilterResolveError> {
        // This is the default for primitive_units
        let params = draw_ctx.push_coord_units(CoordUnits::UserSpaceOnUse);

        match self {
            FilterFunction::Blur(v) => v.to_filter_spec(values, &params),
        }
    }
}

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

    #[test]
    fn parses_blur() {
        assert_eq!(
            FilterFunction::parse_str("blur()").unwrap(),
            FilterFunction::Blur(Blur {
                std_deviation: None
            })
        );

        assert_eq!(
            FilterFunction::parse_str("blur(5px)").unwrap(),
            FilterFunction::Blur(Blur {
                std_deviation: Some(Length::new(5.0, LengthUnit::Px))
            })
        );
    }

    #[test]
    fn invalid_blur_yields_error() {
        assert!(FilterFunction::parse_str("blur(foo)").is_err());
        assert!(FilterFunction::parse_str("blur(42 43)").is_err());
    }
}
<commit_msg>Appease Clippy about unnecessary Result<commit_after>use cssparser::Parser;

use crate::coord_units::CoordUnits;
use crate::drawing_ctx::{DrawingCtx, ViewParams};
use crate::error::*;
use crate::filter::Filter;
use crate::filters::{
    gaussian_blur::GaussianBlur, FilterResolveError, FilterSpec, Primitive, PrimitiveParams,
    ResolvedPrimitive,
};
use crate::length::*;
use crate::parsers::Parse;
use crate::properties::ComputedValues;

/// CSS Filter functions from the Filter Effects Module Level 1
///
/// https://www.w3.org/TR/filter-effects/#filter-functions
#[derive(Debug, Clone, PartialEq)]
pub enum FilterFunction {
    Blur(Blur),
}

/// Parameters for the `blur()` filter function
///
/// https://www.w3.org/TR/filter-effects/#funcdef-filter-blur
#[derive(Debug, Clone, PartialEq)]
pub struct Blur {
    std_deviation: Option<Length<Both>>,
}

fn parse_function<'i, F>(
    parser: &mut Parser<'i, '_>,
    name: &str,
    f: F,
) -> Result<FilterFunction, ParseError<'i>>
where
    F: for<'tt> FnOnce(&mut Parser<'i, 'tt>) -> Result<FilterFunction, ParseError<'i>>,
{
    parser.expect_function_matching(name)?;
    parser.parse_nested_block(f)
}

// This function doesn't fail, but returns a Result like the other parsers, so tell Clippy
// about that.
#[allow(clippy::unnecessary_wraps)]
fn parse_blur<'i>(parser: &mut Parser<'i, '_>) -> Result<FilterFunction, ParseError<'i>> {
    let length = if let Ok(length) = parser.try_parse(|p| Length::parse(p)) {
        Some(length)
    } else {
        None
    };

    Ok(FilterFunction::Blur(Blur {
        std_deviation: length,
    }))
}

impl Blur {
    fn to_filter_spec(
        &self,
        values: &ComputedValues,
        params: &ViewParams,
    ) -> FilterSpec {
        // The 0.0 default is from the spec
        let std_dev = self
            .std_deviation
            .map(|l| l.normalize(values, params))
            .unwrap_or(0.0);

        let user_space_filter = Filter::default().to_user_space(values, params);

        let gaussian_blur = ResolvedPrimitive {
            primitive: Primitive::default(),
            params: PrimitiveParams::GaussianBlur(GaussianBlur {
                std_deviation: (std_dev, std_dev),
                ..GaussianBlur::default()
            }),
        }
        .into_user_space(values, params);

        FilterSpec {
            user_space_filter,
            primitives: vec![gaussian_blur],
        }
    }
}

impl Parse for FilterFunction {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, crate::error::ParseError<'i>> {
        let loc = parser.current_source_location();

        parser
            .try_parse(|p| parse_function(p, "blur", parse_blur))
            .or_else(|_| {
                Err(loc.new_custom_error(ValueErrorKind::parse_error("expected filter function")))
            })
    }
}

impl FilterFunction {
    // If this function starts actually returning an Err, remove this Clippy exception:
    #[allow(clippy::unnecessary_wraps)]
    pub fn to_filter_spec(
        &self,
        values: &ComputedValues,
        draw_ctx: &DrawingCtx,
    ) -> Result<FilterSpec, FilterResolveError> {
        // This is the default for primitive_units
        let params = draw_ctx.push_coord_units(CoordUnits::UserSpaceOnUse);

        match self {
            FilterFunction::Blur(v) => Ok(v.to_filter_spec(values, &params)),
        }
    }
}

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

    #[test]
    fn parses_blur() {
        assert_eq!(
            FilterFunction::parse_str("blur()").unwrap(),
            FilterFunction::Blur(Blur {
                std_deviation: None
            })
        );

        assert_eq!(
            FilterFunction::parse_str("blur(5px)").unwrap(),
            FilterFunction::Blur(Blur {
                std_deviation: Some(Length::new(5.0, LengthUnit::Px))
            })
        );
    }

    #[test]
    fn invalid_blur_yields_error() {
        assert!(FilterFunction::parse_str("blur(foo)").is_err());
        assert!(FilterFunction::parse_str("blur(42 43)").is_err());
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2016 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.

use convert::TryFrom;
use mem;
use ops::{self, Add, Sub};
use usize;

use super::{FusedIterator, TrustedLen};

/// Objects that can be stepped over in both directions.
///
/// The `steps_between` function provides a way to efficiently compare
/// two `Step` objects.
#[unstable(feature = "step_trait",
           reason = "likely to be replaced by finer-grained traits",
           issue = "42168")]
pub trait Step: Clone + PartialOrd + Sized {
    /// Returns the number of steps between two step objects. The count is
    /// inclusive of `start` and exclusive of `end`.
    ///
    /// Returns `None` if it is not possible to calculate `steps_between`
    /// without overflow.
    fn steps_between(start: &Self, end: &Self) -> Option<usize>;

    /// Replaces this step with `1`, returning itself
    fn replace_one(&mut self) -> Self;

    /// Replaces this step with `0`, returning itself
    fn replace_zero(&mut self) -> Self;

    /// Adds one to this step, returning the result
    fn add_one(&self) -> Self;

    /// Subtracts one to this step, returning the result
    fn sub_one(&self) -> Self;

    /// Add an usize, returning None on overflow
    fn add_usize(&self, n: usize) -> Option<Self>;
}

// These are still macro-generated because the integer literals resolve to different types.
macro_rules! step_identical_methods {
    () => {
        #[inline]
        fn replace_one(&mut self) -> Self {
            mem::replace(self, 1)
        }

        #[inline]
        fn replace_zero(&mut self) -> Self {
            mem::replace(self, 0)
        }

        #[inline]
        fn add_one(&self) -> Self {
            Add::add(*self, 1)
        }

        #[inline]
        fn sub_one(&self) -> Self {
            Sub::sub(*self, 1)
        }
    }
}

macro_rules! step_impl_unsigned {
    ($($t:ty)*) => ($(
        #[unstable(feature = "step_trait",
                   reason = "likely to be replaced by finer-grained traits",
                   issue = "42168")]
        impl Step for $t {
            #[inline]
            #[allow(trivial_numeric_casts)]
            fn steps_between(start: &$t, end: &$t) -> Option<usize> {
                if *start < *end {
                    // Note: We assume $t <= usize here
                    Some((*end - *start) as usize)
                } else {
                    Some(0)
                }
            }

            #[inline]
            #[allow(unreachable_patterns)]
            fn add_usize(&self, n: usize) -> Option<Self> {
                match <$t>::try_from(n) {
                    Ok(n_as_t) => self.checked_add(n_as_t),
                    Err(_) => None,
                }
            }

            step_identical_methods!();
        }
    )*)
}
macro_rules! step_impl_signed {
    ($( [$t:ty : $unsigned:ty] )*) => ($(
        #[unstable(feature = "step_trait",
                   reason = "likely to be replaced by finer-grained traits",
                   issue = "42168")]
        impl Step for $t {
            #[inline]
            #[allow(trivial_numeric_casts)]
            fn steps_between(start: &$t, end: &$t) -> Option<usize> {
                if *start < *end {
                    // Note: We assume $t <= isize here
                    // Use .wrapping_sub and cast to usize to compute the
                    // difference that may not fit inside the range of isize.
                    Some((*end as isize).wrapping_sub(*start as isize) as usize)
                } else {
                    Some(0)
                }
            }

            #[inline]
            #[allow(unreachable_patterns)]
            fn add_usize(&self, n: usize) -> Option<Self> {
                match <$unsigned>::try_from(n) {
                    Ok(n_as_unsigned) => {
                        // Wrapping in unsigned space handles cases like
                        // `-120_i8.add_usize(200) == Some(80_i8)`,
                        // even though 200_usize is out of range for i8.
                        let wrapped = (*self as $unsigned).wrapping_add(n_as_unsigned) as $t;
                        if wrapped >= *self {
                            Some(wrapped)
                        } else {
                            None  // Addition overflowed
                        }
                    }
                    Err(_) => None,
                }
            }

            step_identical_methods!();
        }
    )*)
}

macro_rules! step_impl_no_between {
    ($($t:ty)*) => ($(
        #[unstable(feature = "step_trait",
                   reason = "likely to be replaced by finer-grained traits",
                   issue = "42168")]
        impl Step for $t {
            #[inline]
            fn steps_between(_start: &Self, _end: &Self) -> Option<usize> {
                None
            }

            #[inline]
            fn add_usize(&self, n: usize) -> Option<Self> {
                self.checked_add(n as $t)
            }

            step_identical_methods!();
        }
    )*)
}

step_impl_unsigned!(usize u8 u16 u32);
step_impl_signed!([isize: usize] [i8: u8] [i16: u16] [i32: u32]);
#[cfg(target_pointer_width = "64")]
step_impl_unsigned!(u64);
#[cfg(target_pointer_width = "64")]
step_impl_signed!([i64: u64]);
// If the target pointer width is not 64-bits, we
// assume here that it is less than 64-bits.
#[cfg(not(target_pointer_width = "64"))]
step_impl_no_between!(u64 i64);
step_impl_no_between!(u128 i128);

macro_rules! range_exact_iter_impl {
    ($($t:ty)*) => ($(
        #[stable(feature = "rust1", since = "1.0.0")]
        impl ExactSizeIterator for ops::Range<$t> { }
    )*)
}

macro_rules! range_incl_exact_iter_impl {
    ($($t:ty)*) => ($(
        #[unstable(feature = "inclusive_range",
                   reason = "recently added, follows RFC",
                   issue = "28237")]
        impl ExactSizeIterator for ops::RangeInclusive<$t> { }
    )*)
}

macro_rules! range_trusted_len_impl {
    ($($t:ty)*) => ($(
        #[unstable(feature = "trusted_len", issue = "37572")]
        unsafe impl TrustedLen for ops::Range<$t> { }
    )*)
}

macro_rules! range_incl_trusted_len_impl {
    ($($t:ty)*) => ($(
        #[unstable(feature = "inclusive_range",
                   reason = "recently added, follows RFC",
                   issue = "28237")]
        unsafe impl TrustedLen for ops::RangeInclusive<$t> { }
    )*)
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Step> Iterator for ops::Range<A> {
    type Item = A;

    #[inline]
    fn next(&mut self) -> Option<A> {
        if self.start < self.end {
            // We check for overflow here, even though it can't actually
            // happen. Adding this check does however help llvm vectorize loops
            // for some ranges that don't get vectorized otherwise,
            // and this won't actually result in an extra check in an optimized build.
            if let Some(mut n) = self.start.add_usize(1) {
                mem::swap(&mut n, &mut self.start);
                Some(n)
            } else {
                None
            }
        } else {
            None
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        match Step::steps_between(&self.start, &self.end) {
            Some(hint) => (hint, Some(hint)),
            None => (0, None)
        }
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<A> {
        if let Some(plus_n) = self.start.add_usize(n) {
            if plus_n < self.end {
                self.start = plus_n.add_one();
                return Some(plus_n)
            }
        }

        self.start = self.end.clone();
        None
    }
}

// These macros generate `ExactSizeIterator` impls for various range types.
// Range<{u,i}64> and RangeInclusive<{u,i}{32,64,size}> are excluded
// because they cannot guarantee having a length <= usize::MAX, which is
// required by ExactSizeIterator.
range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32);
range_incl_exact_iter_impl!(u8 u16 i8 i16);

// These macros generate `TrustedLen` impls.
//
// They need to guarantee that .size_hint() is either exact, or that
// the upper bound is None when it does not fit the type limits.
range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Step> DoubleEndedIterator for ops::Range<A> {
    #[inline]
    fn next_back(&mut self) -> Option<A> {
        if self.start < self.end {
            self.end = self.end.sub_one();
            Some(self.end.clone())
        } else {
            None
        }
    }
}

#[unstable(feature = "fused", issue = "35602")]
impl<A: Step> FusedIterator for ops::Range<A> {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Step> Iterator for ops::RangeFrom<A> {
    type Item = A;

    #[inline]
    fn next(&mut self) -> Option<A> {
        let mut n = self.start.add_one();
        mem::swap(&mut n, &mut self.start);
        Some(n)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (usize::MAX, None)
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<A> {
        let plus_n = self.start.add_usize(n).expect("overflow in RangeFrom::nth");
        self.start = plus_n.add_one();
        Some(plus_n)
    }
}

#[unstable(feature = "fused", issue = "35602")]
impl<A: Step> FusedIterator for ops::RangeFrom<A> {}

#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<A: Step> Iterator for ops::RangeInclusive<A> {
    type Item = A;

    #[inline]
    fn next(&mut self) -> Option<A> {
        use cmp::Ordering::*;

        match self.start.partial_cmp(&self.end) {
            Some(Less) => {
                let n = self.start.add_one();
                Some(mem::replace(&mut self.start, n))
            },
            Some(Equal) => {
                let last = self.start.replace_one();
                self.end.replace_zero();
                Some(last)
            },
            _ => None,
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        if !(self.start <= self.end) {
            return (0, Some(0));
        }

        match Step::steps_between(&self.start, &self.end) {
            Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
            None => (0, None),
        }
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<A> {
        if let Some(plus_n) = self.start.add_usize(n) {
            use cmp::Ordering::*;

            match plus_n.partial_cmp(&self.end) {
                Some(Less) => {
                    self.start = plus_n.add_one();
                    return Some(plus_n)
                }
                Some(Equal) => {
                    self.start.replace_one();
                    self.end.replace_zero();
                    return Some(plus_n)
                }
                _ => {}
            }
        }

        self.start.replace_one();
        self.end.replace_zero();
        None
    }
}

#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
    #[inline]
    fn next_back(&mut self) -> Option<A> {
        use cmp::Ordering::*;

        match self.start.partial_cmp(&self.end) {
            Some(Less) => {
                let n = self.end.sub_one();
                Some(mem::replace(&mut self.end, n))
            },
            Some(Equal) => {
                let last = self.end.replace_zero();
                self.start.replace_one();
                Some(last)
            },
            _ => None,
        }
    }
}

#[unstable(feature = "fused", issue = "35602")]
impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}
<commit_msg>Add min and max specialisations for RangeInclusive<commit_after>// Copyright 2013-2016 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.

use convert::TryFrom;
use mem;
use ops::{self, Add, Sub};
use usize;

use super::{FusedIterator, TrustedLen};

/// Objects that can be stepped over in both directions.
///
/// The `steps_between` function provides a way to efficiently compare
/// two `Step` objects.
#[unstable(feature = "step_trait",
           reason = "likely to be replaced by finer-grained traits",
           issue = "42168")]
pub trait Step: Clone + PartialOrd + Sized {
    /// Returns the number of steps between two step objects. The count is
    /// inclusive of `start` and exclusive of `end`.
    ///
    /// Returns `None` if it is not possible to calculate `steps_between`
    /// without overflow.
    fn steps_between(start: &Self, end: &Self) -> Option<usize>;

    /// Replaces this step with `1`, returning itself
    fn replace_one(&mut self) -> Self;

    /// Replaces this step with `0`, returning itself
    fn replace_zero(&mut self) -> Self;

    /// Adds one to this step, returning the result
    fn add_one(&self) -> Self;

    /// Subtracts one to this step, returning the result
    fn sub_one(&self) -> Self;

    /// Add an usize, returning None on overflow
    fn add_usize(&self, n: usize) -> Option<Self>;
}

// These are still macro-generated because the integer literals resolve to different types.
macro_rules! step_identical_methods {
    () => {
        #[inline]
        fn replace_one(&mut self) -> Self {
            mem::replace(self, 1)
        }

        #[inline]
        fn replace_zero(&mut self) -> Self {
            mem::replace(self, 0)
        }

        #[inline]
        fn add_one(&self) -> Self {
            Add::add(*self, 1)
        }

        #[inline]
        fn sub_one(&self) -> Self {
            Sub::sub(*self, 1)
        }
    }
}

macro_rules! step_impl_unsigned {
    ($($t:ty)*) => ($(
        #[unstable(feature = "step_trait",
                   reason = "likely to be replaced by finer-grained traits",
                   issue = "42168")]
        impl Step for $t {
            #[inline]
            #[allow(trivial_numeric_casts)]
            fn steps_between(start: &$t, end: &$t) -> Option<usize> {
                if *start < *end {
                    // Note: We assume $t <= usize here
                    Some((*end - *start) as usize)
                } else {
                    Some(0)
                }
            }

            #[inline]
            #[allow(unreachable_patterns)]
            fn add_usize(&self, n: usize) -> Option<Self> {
                match <$t>::try_from(n) {
                    Ok(n_as_t) => self.checked_add(n_as_t),
                    Err(_) => None,
                }
            }

            step_identical_methods!();
        }
    )*)
}
macro_rules! step_impl_signed {
    ($( [$t:ty : $unsigned:ty] )*) => ($(
        #[unstable(feature = "step_trait",
                   reason = "likely to be replaced by finer-grained traits",
                   issue = "42168")]
        impl Step for $t {
            #[inline]
            #[allow(trivial_numeric_casts)]
            fn steps_between(start: &$t, end: &$t) -> Option<usize> {
                if *start < *end {
                    // Note: We assume $t <= isize here
                    // Use .wrapping_sub and cast to usize to compute the
                    // difference that may not fit inside the range of isize.
                    Some((*end as isize).wrapping_sub(*start as isize) as usize)
                } else {
                    Some(0)
                }
            }

            #[inline]
            #[allow(unreachable_patterns)]
            fn add_usize(&self, n: usize) -> Option<Self> {
                match <$unsigned>::try_from(n) {
                    Ok(n_as_unsigned) => {
                        // Wrapping in unsigned space handles cases like
                        // `-120_i8.add_usize(200) == Some(80_i8)`,
                        // even though 200_usize is out of range for i8.
                        let wrapped = (*self as $unsigned).wrapping_add(n_as_unsigned) as $t;
                        if wrapped >= *self {
                            Some(wrapped)
                        } else {
                            None  // Addition overflowed
                        }
                    }
                    Err(_) => None,
                }
            }

            step_identical_methods!();
        }
    )*)
}

macro_rules! step_impl_no_between {
    ($($t:ty)*) => ($(
        #[unstable(feature = "step_trait",
                   reason = "likely to be replaced by finer-grained traits",
                   issue = "42168")]
        impl Step for $t {
            #[inline]
            fn steps_between(_start: &Self, _end: &Self) -> Option<usize> {
                None
            }

            #[inline]
            fn add_usize(&self, n: usize) -> Option<Self> {
                self.checked_add(n as $t)
            }

            step_identical_methods!();
        }
    )*)
}

step_impl_unsigned!(usize u8 u16 u32);
step_impl_signed!([isize: usize] [i8: u8] [i16: u16] [i32: u32]);
#[cfg(target_pointer_width = "64")]
step_impl_unsigned!(u64);
#[cfg(target_pointer_width = "64")]
step_impl_signed!([i64: u64]);
// If the target pointer width is not 64-bits, we
// assume here that it is less than 64-bits.
#[cfg(not(target_pointer_width = "64"))]
step_impl_no_between!(u64 i64);
step_impl_no_between!(u128 i128);

macro_rules! range_exact_iter_impl {
    ($($t:ty)*) => ($(
        #[stable(feature = "rust1", since = "1.0.0")]
        impl ExactSizeIterator for ops::Range<$t> { }
    )*)
}

macro_rules! range_incl_exact_iter_impl {
    ($($t:ty)*) => ($(
        #[unstable(feature = "inclusive_range",
                   reason = "recently added, follows RFC",
                   issue = "28237")]
        impl ExactSizeIterator for ops::RangeInclusive<$t> { }
    )*)
}

macro_rules! range_trusted_len_impl {
    ($($t:ty)*) => ($(
        #[unstable(feature = "trusted_len", issue = "37572")]
        unsafe impl TrustedLen for ops::Range<$t> { }
    )*)
}

macro_rules! range_incl_trusted_len_impl {
    ($($t:ty)*) => ($(
        #[unstable(feature = "inclusive_range",
                   reason = "recently added, follows RFC",
                   issue = "28237")]
        unsafe impl TrustedLen for ops::RangeInclusive<$t> { }
    )*)
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Step> Iterator for ops::Range<A> {
    type Item = A;

    #[inline]
    fn next(&mut self) -> Option<A> {
        if self.start < self.end {
            // We check for overflow here, even though it can't actually
            // happen. Adding this check does however help llvm vectorize loops
            // for some ranges that don't get vectorized otherwise,
            // and this won't actually result in an extra check in an optimized build.
            if let Some(mut n) = self.start.add_usize(1) {
                mem::swap(&mut n, &mut self.start);
                Some(n)
            } else {
                None
            }
        } else {
            None
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        match Step::steps_between(&self.start, &self.end) {
            Some(hint) => (hint, Some(hint)),
            None => (0, None)
        }
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<A> {
        if let Some(plus_n) = self.start.add_usize(n) {
            if plus_n < self.end {
                self.start = plus_n.add_one();
                return Some(plus_n)
            }
        }

        self.start = self.end.clone();
        None
    }
}

// These macros generate `ExactSizeIterator` impls for various range types.
// Range<{u,i}64> and RangeInclusive<{u,i}{32,64,size}> are excluded
// because they cannot guarantee having a length <= usize::MAX, which is
// required by ExactSizeIterator.
range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32);
range_incl_exact_iter_impl!(u8 u16 i8 i16);

// These macros generate `TrustedLen` impls.
//
// They need to guarantee that .size_hint() is either exact, or that
// the upper bound is None when it does not fit the type limits.
range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);
range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64);

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Step> DoubleEndedIterator for ops::Range<A> {
    #[inline]
    fn next_back(&mut self) -> Option<A> {
        if self.start < self.end {
            self.end = self.end.sub_one();
            Some(self.end.clone())
        } else {
            None
        }
    }
}

#[unstable(feature = "fused", issue = "35602")]
impl<A: Step> FusedIterator for ops::Range<A> {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Step> Iterator for ops::RangeFrom<A> {
    type Item = A;

    #[inline]
    fn next(&mut self) -> Option<A> {
        let mut n = self.start.add_one();
        mem::swap(&mut n, &mut self.start);
        Some(n)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (usize::MAX, None)
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<A> {
        let plus_n = self.start.add_usize(n).expect("overflow in RangeFrom::nth");
        self.start = plus_n.add_one();
        Some(plus_n)
    }
}

#[unstable(feature = "fused", issue = "35602")]
impl<A: Step> FusedIterator for ops::RangeFrom<A> {}

#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<A: Step> Iterator for ops::RangeInclusive<A> {
    type Item = A;

    #[inline]
    fn next(&mut self) -> Option<A> {
        use cmp::Ordering::*;

        match self.start.partial_cmp(&self.end) {
            Some(Less) => {
                let n = self.start.add_one();
                Some(mem::replace(&mut self.start, n))
            },
            Some(Equal) => {
                let last = self.start.replace_one();
                self.end.replace_zero();
                Some(last)
            },
            _ => None,
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        if !(self.start <= self.end) {
            return (0, Some(0));
        }

        match Step::steps_between(&self.start, &self.end) {
            Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
            None => (0, None),
        }
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<A> {
        if let Some(plus_n) = self.start.add_usize(n) {
            use cmp::Ordering::*;

            match plus_n.partial_cmp(&self.end) {
                Some(Less) => {
                    self.start = plus_n.add_one();
                    return Some(plus_n)
                }
                Some(Equal) => {
                    self.start.replace_one();
                    self.end.replace_zero();
                    return Some(plus_n)
                }
                _ => {}
            }
        }

        self.start.replace_one();
        self.end.replace_zero();
        None
    }

    #[inline]
    fn min(self) -> Option<A> {
        Some(self.start)
    }

    #[inline]
    fn max(self) -> Option<A> {
        Some(self.end)
    }
}

#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
    #[inline]
    fn next_back(&mut self) -> Option<A> {
        use cmp::Ordering::*;

        match self.start.partial_cmp(&self.end) {
            Some(Less) => {
                let n = self.end.sub_one();
                Some(mem::replace(&mut self.end, n))
            },
            Some(Equal) => {
                let last = self.end.replace_zero();
                self.start.replace_one();
                Some(last)
            },
            _ => None,
        }
    }
}

#[unstable(feature = "fused", issue = "35602")]
impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}
<|endoftext|>


<commit_before>use index::btree::dump::dump_tree;
use index::btree::external::ExtNode;
use index::btree::internal::InNode;
use index::btree::node::is_node_locked;
use index::btree::node::read_node;
use index::btree::node::read_unchecked;
use index::btree::node::write_node;
use index::btree::node::write_non_empty;
use index::btree::node::write_targeted;
use index::btree::node::EmptyNode;
use index::btree::node::Node;
use index::btree::node::NodeData;
use index::btree::node::NodeWriteGuard;
use index::btree::search::mut_search;
use index::btree::search::MutSearchResult;
use index::btree::LevelTree;
use index::btree::NodeCellRef;
use index::btree::{external, BPlusTree};
use index::lsmtree::tree::{LEVEL_2, LEVEL_3, LEVEL_PAGE_DIFF_MULTIPLIER};
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use smallvec::SmallVec;
use std::cmp::min;
use std::collections::{BTreeSet, HashMap, HashSet};
use std::fmt::Debug;
use std::mem;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::Arc;

enum Selection<KS, PS>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    Selected(Vec<NodeWriteGuard<KS, PS>>),
    Innode(NodeCellRef),
}

fn select<KS, PS>(node: &NodeCellRef) -> Vec<NodeWriteGuard<KS, PS>>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let search = mut_search::<KS, PS>(node, &smallvec!());
    match search {
        MutSearchResult::External => {
            let first_node = write_node(node);
            let mut collected_keys = first_node.len();
            let mut collected = vec![first_node];
            let target_keys = min(KS::slice_len() * LEVEL_PAGE_DIFF_MULTIPLIER, LEVEL_3);
            let target_guards = LEVEL_2;
            while collected_keys < target_keys && collected.len() < target_guards {
                let right = write_node(
                    collected
                        .last_mut()
                        .unwrap()
                        .right_ref_mut_no_empty()
                        .unwrap(),
                );
                if right.is_none() {
                    break;
                } else {
                    collected_keys += right.len();
                    collected.push(right);
                }
            }
            return collected;
        }
        MutSearchResult::Internal(node) => select::<KS, PS>(&node),
    }
}

fn prune_selected<'a, KS, PS>(node: &NodeCellRef, bound: &EntryKey) -> Vec<NodeCellRef>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let first_search = mut_search::<KS, PS>(node, &smallvec!());
    match first_search {
        MutSearchResult::Internal(sub_node_ref) => {
            let sub_node = read_unchecked::<KS, PS>(&sub_node_ref);
            if !sub_node.is_empty_node() && !sub_node.is_ext() {
                prune_selected::<KS, PS>(&sub_node_ref, bound);
            }
        }
        MutSearchResult::External => unreachable!(),
    };
    let mut prev_node_guard: Option<NodeWriteGuard<KS, PS>> = None;
    let mut page = write_node::<KS, PS>(&node);
    let mut next_live_ptrs = None;
    let mut emptying_nodes = vec![];
    let mut empty_nodes = vec![];
    let select_live = |page: &NodeWriteGuard<KS, PS>| {
        page.innode().ptrs.as_slice_immute()[..page.len() + 1]
            .iter()
            .enumerate()
            .filter_map(|(i, sub_level)| {
                if !read_unchecked::<KS, PS>(sub_level).is_empty_node() {
                    Some((i, sub_level.clone()))
                } else {
                    None
                }
            })
            .collect()
    };
    let mut next_non_empty = |page: &NodeWriteGuard<KS, PS>, empty_nodes: &mut Vec<_>| {
        let mut next = page.right_ref().cloned();
        while let Some(next_ref) = next {
            let guard = write_node::<KS, PS>(&next_ref);
            next = guard.right_ref().cloned();
            let live_ptrs: HashMap<_, _> = select_live(&guard);
            if live_ptrs.is_empty() {
                empty_nodes.push(guard);
            } else {
                return (guard, live_ptrs);
            }
        };
        unreachable!()
    };
    loop {
        let page_len = page.len();
        let page_right_ref = page.right_ref().unwrap().clone();
        if !page.is_empty_node() {
            let mut live_ptrs: HashMap<_, _> = next_live_ptrs.unwrap_or_else(|| select_live(&page));
            let is_empty = live_ptrs.is_empty();
            if !is_empty {
                let emptying = {
                    let mut innode = page.innode_mut();
                    let mut new_keys = KS::init();
                    let mut new_ptrs = PS::init();
                    {
                        let keys: Vec<&mut _> = innode.keys.as_slice()[..page_len]
                            .iter_mut()
                            .enumerate()
                            .filter(|(i, _)| live_ptrs.contains_key(&i))
                            .map(|(_, k)| k)
                            .collect();
                        debug!("Prune filtered page have keys {:?}", &keys);
                        debug_assert_eq!(live_ptrs.len(), keys.len() + 1);
                        innode.len = keys.len();
                        let new_keys = new_keys.as_slice();
                        let new_ptrs = new_ptrs.as_slice();
                        for (i, key) in keys.into_iter().enumerate() {
                            debug_assert!(key > &mut smallvec!(0));
                            mem::swap(&mut new_keys[i], key);
                        }
                        for (i, (_, ptr)) in live_ptrs.into_iter().enumerate() {
                            debug_assert!(!ptr.is_default());
                            mem::replace(&mut new_ptrs[i], ptr);
                        }
                    }
                    innode.keys = new_keys;
                    innode.ptrs = new_ptrs;
                    innode.len == 0
                };
                if emptying {
                    // current innode have one ptr and no keys
                    // need to merge with the right page
                    // if the right page is full, partial of the right page will be moved to the current page
                    // merging right page will also been cleaned

                }
            }
            let (next_page, ptrs) = next_non_empty(&page, &mut empty_nodes);
            if !is_empty {
                if page.right_bound() >= bound {
                    break;
                } else {
                    prev_node_guard = Some(page);
                }
            } else {
                empty_nodes.push(page);
            }
            page = next_page;
            next_live_ptrs = Some(ptrs);
        } else {
            unreachable!();
        }
    }
    let last_page_ref = page.node_ref();
    for empty in &mut empty_nodes {
        // make nodes empty and set its next ptr to last non empty node
        **empty = NodeData::Empty(box EmptyNode {
            left: None,
            right: last_page_ref.clone(),
        });
    }
    emptying_nodes
}

pub fn level_merge<KS, PS>(src_tree: &BPlusTree<KS, PS>, dest_tree: &LevelTree) -> usize
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let mut left_most_leaf_guards = select::<KS, PS>(&src_tree.get_root());
    let merge_page_len = left_most_leaf_guards.len();
    let mut num_keys_removed = 0;
    let left_most_id = left_most_leaf_guards.first().unwrap().ext_id();
    let prune_bound = left_most_leaf_guards.last().unwrap().right_bound().clone();

    debug!("Merge selected {} pages", left_most_leaf_guards.len());
    if cfg!(debug_assertions) {
        if left_most_id != src_tree.head_page_id {
            dump_tree(src_tree, "level_lsm_merge_failure_dump.json");
        }
    }
    debug_assert_eq!(
        left_most_id,
        src_tree.head_page_id,
        "{}",
        left_most_leaf_guards.first().unwrap().type_name()
    );

    // merge to dest_tree
    {
        let mut deleted_keys = src_tree.deleted.write();
        let mut merged_deleted_keys = vec![];
        let keys: Vec<EntryKey> = left_most_leaf_guards
            .iter()
            .filter(|&g| !g.is_empty_node())
            .map(|g| &g.keys()[..g.len()])
            .flatten()
            .filter(|&k| {
                if deleted_keys.contains(k) {
                    merged_deleted_keys.push(k.clone());
                    false
                } else {
                    true
                }
            })
            .cloned()
            .collect_vec();
        num_keys_removed = keys.len();
        debug!("Merge selected keys are {:?}", &keys);
        dest_tree.merge_with_keys(box keys);
        for rk in &merged_deleted_keys {
            deleted_keys.remove(rk);
        }
    }

    // adjust leaf left, right references
    {
        let right_right_most = left_most_leaf_guards
            .last()
            .unwrap()
            .right_ref()
            .unwrap()
            .clone();

        let left_left_most = left_most_leaf_guards
            .first()
            .unwrap()
            .left_ref()
            .unwrap()
            .clone();

        debug_assert!(read_unchecked::<KS, PS>(&left_left_most).is_none());
        debug_assert!(read_unchecked::<KS, PS>(&right_right_most).is_ext());
        debug_assert!(!Arc::ptr_eq(
            &right_right_most.inner,
            &left_most_leaf_guards.last().unwrap().node_ref().inner
        ));

        for mut g in &mut left_most_leaf_guards {
            external::make_deleted(&g.ext_id());
            **g = NodeData::Empty(box EmptyNode {
                left: Some(left_left_most.clone()),
                right: right_right_most.clone(),
            });
        }

        let mut new_first_node = write_node::<KS, PS>(&right_right_most);
        let mut new_first_node_ext = new_first_node.extnode_mut();
        new_first_node_ext.id = src_tree.head_page_id;
        new_first_node_ext.prev = left_left_most;

        debug_assert!(&new_first_node_ext.right_bound > &prune_bound);

        ExtNode::<KS, PS>::make_changed(&right_right_most, src_tree);
    }

    // cleanup upper level references
    prune_selected::<KS, PS>(&src_tree.get_root(), &prune_bound);

    src_tree.len.fetch_sub(num_keys_removed, Relaxed);

    merge_page_len
}
<commit_msg>trying co cope with emptying keys<commit_after>use index::btree::dump::dump_tree;
use index::btree::external::ExtNode;
use index::btree::internal::InNode;
use index::btree::node::is_node_locked;
use index::btree::node::read_node;
use index::btree::node::read_unchecked;
use index::btree::node::write_node;
use index::btree::node::write_non_empty;
use index::btree::node::write_targeted;
use index::btree::node::EmptyNode;
use index::btree::node::Node;
use index::btree::node::NodeData;
use index::btree::node::NodeWriteGuard;
use index::btree::search::mut_search;
use index::btree::search::MutSearchResult;
use index::btree::LevelTree;
use index::btree::NodeCellRef;
use index::btree::{external, BPlusTree};
use index::lsmtree::tree::{LEVEL_2, LEVEL_3, LEVEL_PAGE_DIFF_MULTIPLIER};
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use smallvec::SmallVec;
use std::cmp::min;
use std::collections::{BTreeSet, HashMap, HashSet};
use std::fmt::Debug;
use std::mem;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::Arc;

enum Selection<KS, PS>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    Selected(Vec<NodeWriteGuard<KS, PS>>),
    Innode(NodeCellRef),
}

struct KeyAltered {
    new_key: EntryKey,
    search_key: EntryKey,
    ptr: NodeCellRef
}

fn select<KS, PS>(node: &NodeCellRef) -> Vec<NodeWriteGuard<KS, PS>>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let search = mut_search::<KS, PS>(node, &smallvec!());
    match search {
        MutSearchResult::External => {
            let first_node = write_node(node);
            let mut collected_keys = first_node.len();
            let mut collected = vec![first_node];
            let target_keys = min(KS::slice_len() * LEVEL_PAGE_DIFF_MULTIPLIER, LEVEL_3);
            let target_guards = LEVEL_2;
            while collected_keys < target_keys && collected.len() < target_guards {
                let right = write_node(
                    collected
                        .last_mut()
                        .unwrap()
                        .right_ref_mut_no_empty()
                        .unwrap(),
                );
                if right.is_none() {
                    break;
                } else {
                    collected_keys += right.len();
                    collected.push(right);
                }
            }
            return collected;
        }
        MutSearchResult::Internal(node) => select::<KS, PS>(&node),
    }
}

fn prune_selected<'a, KS, PS>(node: &NodeCellRef, bound: &EntryKey) -> Vec<KeyAltered>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let first_search = mut_search::<KS, PS>(node, &smallvec!());
    match first_search {
        MutSearchResult::Internal(sub_node_ref) => {
            let sub_node = read_unchecked::<KS, PS>(&sub_node_ref);
            if !sub_node.is_empty_node() && !sub_node.is_ext() {
                prune_selected::<KS, PS>(&sub_node_ref, bound);
            }
        }
        MutSearchResult::External => unreachable!(),
    };
    let mut prev_node_guard: Option<NodeWriteGuard<KS, PS>> = None;
    let mut page = write_node::<KS, PS>(&node);
    let mut next_live_ptrs = None;
    let mut altered = vec![];
    let mut empty_nodes = vec![];
    let select_live = |page: &NodeWriteGuard<KS, PS>| {
        page.innode().ptrs.as_slice_immute()[..page.len() + 1]
            .iter()
            .enumerate()
            .filter_map(|(i, sub_level)| {
                if !read_unchecked::<KS, PS>(sub_level).is_empty_node() {
                    Some((i, sub_level.clone()))
                } else {
                    None
                }
            })
            .collect()
    };
    let mut next_non_empty = |page: &NodeWriteGuard<KS, PS>, empty_nodes: &mut Vec<_>| {
        let mut next = page.right_ref().cloned();
        while let Some(next_ref) = next {
            let guard = write_node::<KS, PS>(&next_ref);
            next = guard.right_ref().cloned();
            let live_ptrs: HashMap<_, _> = select_live(&guard);
            if live_ptrs.is_empty() {
                empty_nodes.push(guard);
            } else {
                return (guard, live_ptrs);
            }
        };
        unreachable!()
    };
    let preserve_live = |innode: &mut InNode<KS, PS>, live_ptrs: HashMap<usize, NodeCellRef>| {
        let mut new_keys = KS::init();
        let mut new_ptrs = PS::init();
        {
            let keys: Vec<&mut _> = innode.keys.as_slice()[..innode.len]
                .iter_mut()
                .enumerate()
                .filter(|(i, _)| live_ptrs.contains_key(&i))
                .map(|(_, k)| k)
                .collect();
            debug!("Prune filtered page have keys {:?}", &keys);
            debug_assert_eq!(live_ptrs.len(), keys.len() + 1);
            innode.len = keys.len();
            let new_keys = new_keys.as_slice();
            let new_ptrs = new_ptrs.as_slice();
            for (i, key) in keys.into_iter().enumerate() {
                debug_assert!(key > &mut smallvec!(0));
                mem::swap(&mut new_keys[i], key);
            }
            for (i, (_, ptr)) in live_ptrs.into_iter().enumerate() {
                debug_assert!(!ptr.is_default());
                mem::replace(&mut new_ptrs[i], ptr);
            }
        }
        innode.keys = new_keys;
        innode.ptrs = new_ptrs;
        innode.len == 0
    };
    loop {
        let page_right_ref = page.right_ref().unwrap().clone();
        if !page.is_empty_node() {
            let mut live_ptrs: HashMap<_, _> = next_live_ptrs.unwrap_or_else(|| select_live(&page));
            let is_empty = live_ptrs.is_empty();
            if !is_empty {
                let emptying = {
                    let mut innode = page.innode_mut();
                    preserve_live(&mut innode, live_ptrs)
                };
                if emptying {
                    // current innode have one ptr and no keys
                    // need to merge with the right page
                    // if the right page is full, partial of the right page will be moved to the current page
                    // merging right page will also been cleaned
                    let (mut next_guard, next_ptrs) = next_non_empty(&page, &mut empty_nodes);
                    let mid = next_guard.len() / 2;
                    let next_ref = next_guard.node_ref().clone();
                    let page_ref = page.node_ref().clone();
                    let mut page_innode = page.innode_mut();
                    let next_node_emptying = preserve_live(&mut next_guard.innode_mut(), next_ptrs);
                    page_innode.keys.as_slice()[0] = page_innode.right_bound.clone();
                    if next_guard.len() >= KS::slice_len() {
                        // will overflow if merged, have to rebalance right node contents with current node
                        let mut next_innode = next_guard.innode_mut();
                        let next_search_key = next_innode.keys.as_slice()[0].clone();
                        // move next node keys and ptrs to current node
                        for i in 0..mid {
                            mem::swap(&mut page_innode.keys.as_slice()[i + 1], &mut next_innode.keys.as_slice()[i]);
                            mem::swap(&mut page_innode.ptrs.as_slice()[i + 1], &mut next_innode.ptrs.as_slice()[i]);
                        }
                        for i in mid..next_innode.len {
                            next_innode.keys.as_slice().swap(i, i - mid);
                            next_innode.ptrs.as_slice().swap(i, i - mid);
                        }
                        next_innode.len -= mid;
                        page_innode.len += mid;
                        page_innode.right_bound = mem::replace(&mut page_innode.keys.as_slice()[mid], smallvec!());
                        page_innode.len = 1 + mid;
                        altered.push(KeyAltered {
                            new_key: page_innode.right_bound.clone(),
                            search_key: next_search_key,
                            ptr: next_ref
                        });

                    } else {
                        // Can move right page contents to current node and empty next node
                        {
                            let mut next_innode = next_guard.innode_mut();
                            let next_node_len = next_innode.len;
                            for i in 0..next_innode.len {
                                mem::swap(&mut page_innode.keys.as_slice()[i + 1], &mut next_innode.keys.as_slice()[i]);
                                mem::swap(&mut page_innode.ptrs.as_slice()[i + 1], &mut next_innode.ptrs.as_slice()[i]);
                            }
                            mem::swap(&mut page_innode.ptrs.as_slice()[next_node_len + 1], &mut next_innode.ptrs.as_slice()[next_node_len]);
                            page_innode.len = 1 + next_node_len;
                            page_innode.right = next_innode.right.clone();
                            page_innode.right_bound = next_innode.right_bound.clone();
                        }
                        *next_guard = NodeData::Empty(box EmptyNode {
                            left: None,
                            right: page_ref
                        });
                    }
                }
            }
            let (next_page, ptrs) = next_non_empty(&page, &mut empty_nodes);
            if !is_empty {
                if page.right_bound() >= bound {
                    break;
                } else {
                    prev_node_guard = Some(page);
                }
            } else {
                empty_nodes.push(page);
            }
            page = next_page;
            next_live_ptrs = Some(ptrs);
        } else {
            unreachable!();
        }
    }
    let last_page_ref = page.node_ref();
    for empty in &mut empty_nodes {
        // make nodes empty and set its next ptr to last non empty node
        **empty = NodeData::Empty(box EmptyNode {
            left: None,
            right: last_page_ref.clone(),
        });
    }
    altered
}

pub fn level_merge<KS, PS>(src_tree: &BPlusTree<KS, PS>, dest_tree: &LevelTree) -> usize
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let mut left_most_leaf_guards = select::<KS, PS>(&src_tree.get_root());
    let merge_page_len = left_most_leaf_guards.len();
    let mut num_keys_removed = 0;
    let left_most_id = left_most_leaf_guards.first().unwrap().ext_id();
    let prune_bound = left_most_leaf_guards.last().unwrap().right_bound().clone();

    debug!("Merge selected {} pages", left_most_leaf_guards.len());
    if cfg!(debug_assertions) {
        if left_most_id != src_tree.head_page_id {
            dump_tree(src_tree, "level_lsm_merge_failure_dump.json");
        }
    }
    debug_assert_eq!(
        left_most_id,
        src_tree.head_page_id,
        "{}",
        left_most_leaf_guards.first().unwrap().type_name()
    );

    // merge to dest_tree
    {
        let mut deleted_keys = src_tree.deleted.write();
        let mut merged_deleted_keys = vec![];
        let keys: Vec<EntryKey> = left_most_leaf_guards
            .iter()
            .filter(|&g| !g.is_empty_node())
            .map(|g| &g.keys()[..g.len()])
            .flatten()
            .filter(|&k| {
                if deleted_keys.contains(k) {
                    merged_deleted_keys.push(k.clone());
                    false
                } else {
                    true
                }
            })
            .cloned()
            .collect_vec();
        num_keys_removed = keys.len();
        debug!("Merge selected keys are {:?}", &keys);
        dest_tree.merge_with_keys(box keys);
        for rk in &merged_deleted_keys {
            deleted_keys.remove(rk);
        }
    }

    // adjust leaf left, right references
    {
        let right_right_most = left_most_leaf_guards
            .last()
            .unwrap()
            .right_ref()
            .unwrap()
            .clone();

        let left_left_most = left_most_leaf_guards
            .first()
            .unwrap()
            .left_ref()
            .unwrap()
            .clone();

        debug_assert!(read_unchecked::<KS, PS>(&left_left_most).is_none());
        debug_assert!(read_unchecked::<KS, PS>(&right_right_most).is_ext());
        debug_assert!(!Arc::ptr_eq(
            &right_right_most.inner,
            &left_most_leaf_guards.last().unwrap().node_ref().inner
        ));

        for mut g in &mut left_most_leaf_guards {
            external::make_deleted(&g.ext_id());
            **g = NodeData::Empty(box EmptyNode {
                left: Some(left_left_most.clone()),
                right: right_right_most.clone(),
            });
        }

        let mut new_first_node = write_node::<KS, PS>(&right_right_most);
        let mut new_first_node_ext = new_first_node.extnode_mut();
        new_first_node_ext.id = src_tree.head_page_id;
        new_first_node_ext.prev = left_left_most;

        debug_assert!(&new_first_node_ext.right_bound > &prune_bound);

        ExtNode::<KS, PS>::make_changed(&right_right_most, src_tree);
    }

    // cleanup upper level references
    prune_selected::<KS, PS>(&src_tree.get_root(), &prune_bound);

    src_tree.len.fetch_sub(num_keys_removed, Relaxed);

    merge_page_len
}
<|endoftext|>


<commit_before>use std::collections::hash_map::{HashMap, Occupied, Vacant};
use super::function::Function;

/// Holds a number of variables, functions and their values.
#[deriving(Clone)]
pub struct Scope<'a> {
	var_values: Vec<f32>, // values of vars by id
	vars: HashMap<&'a str, uint>, // map of var name -> var id

	functions: HashMap<&'a str, &'a Box<Function + 'a>>,
}

impl<'a> Scope<'a> {
	/// Constructs an empty scope object.
	pub fn new() -> Scope<'a> {
		Scope {
			var_values: Vec::new(),
			vars: HashMap::new(),
			functions: HashMap::new(),
		}
	}

	/// Returns a uint identifier which can be passed to set_var to quickly update the value of a
	/// variable.
	pub fn var_id(&self, var: &'a str) -> Option<uint> {
		match self.vars.get(&var) {
			Some(v) => Some(*v),
			None => None,
		}
	}

	/// Sets a variable to an id retrieved from var_id. Return value indicates whether it was set
	/// sucessfully or not.
	pub fn set_var(&mut self, var_id: uint, value: f32) -> bool {
		if var_id > self.var_values.len() {
			return false;
		}
		self.var_values[var_id] = value;
		true
	}

	/// Returns the value of a variable by id.
	pub fn get_var(&self, var_id: uint) -> Option<f32> {
		if var_id >= self.var_values.len() {
			None
		} else {
			Some(self.var_values[var_id])
		}
	}

	/// Sets a variable to a specified value, creating the variable if it does not exist.
	pub fn define_var(&mut self, var: &'a str, value: f32) {
		let nv = self.vars.len();
		match self.vars.entry(var) {
			Occupied(entry) => {
				self.var_values[*entry.get()] = value;
			},
			Vacant(entry) => {
				entry.set(nv);
				self.var_values.push(value);
			},
		}
	}

	/// Returns the number of variables set in the scope.
	pub fn num_vars(&self) -> uint {
		self.vars.len()
	}

	/// Defines a function in the scope.
	pub fn define_function(&mut self, name: &'a str, func: &'a Box<Function + 'a>) {
		self.functions[name] = func;
	}

	/// Gets a function previously defined in the scope.
	pub fn get_function(&self, name: &'a str) -> Option<&'a Box<Function + 'a>> {
		match self.functions.get(&name) {
			Some(v) => Some(*v),
			None => None,
		}
	}
}
<commit_msg>Pointer fixups<commit_after>use std::collections::hash_map::{HashMap, Occupied, Vacant};
use super::function::Function;

/// Holds a number of variables, functions and their values.
#[deriving(Clone)]
pub struct Scope<'a> {
	var_values: Vec<f32>, // values of vars by id
	vars: HashMap<&'a str, uint>, // map of var name -> var id

	functions: HashMap<&'a str, &'a Box<Function + 'a>>,
}

impl<'a> Scope<'a> {
	/// Constructs an empty scope object.
	pub fn new() -> Scope<'a> {
		Scope {
			var_values: Vec::new(),
			vars: HashMap::new(),
			functions: HashMap::new(),
		}
	}

	/// Returns a uint identifier which can be passed to set_var to quickly update the value of a
	/// variable.
	pub fn var_id(&self, var: &'a str) -> Option<uint> {
		match self.vars.get(&var) {
			Some(v) => Some(*v),
			None => None,
		}
	}

	/// Sets a variable to an id retrieved from var_id. Return value indicates whether it was set
	/// sucessfully or not.
	pub fn set_var(&mut self, var_id: uint, value: f32) -> bool {
		if var_id > self.var_values.len() {
			return false;
		}
		self.var_values[var_id] = value;
		true
	}

	/// Returns the value of a variable by id.
	pub fn get_var(&self, var_id: uint) -> Option<f32> {
		if var_id >= self.var_values.len() {
			None
		} else {
			Some(self.var_values[var_id])
		}
	}

	/// Sets a variable to a specified value, creating the variable if it does not exist.
	pub fn define_var(&mut self, var: &'a str, value: f32) {
		let nv = self.vars.len();
		match self.vars.entry(var) {
			Occupied(entry) => {
				self.var_values[*entry.get()] = value;
			},
			Vacant(entry) => {
				entry.set(nv);
				self.var_values.push(value);
			},
		}
	}

	/// Returns the number of variables set in the scope.
	pub fn num_vars(&self) -> uint {
		self.vars.len()
	}

	/// Defines a function in the scope.
	pub fn define_function(&mut self, name: &'a str, func: &'a Box<Function>) {
		self.functions[name] = func;
	}

	/// Gets a function previously defined in the scope.
	pub fn get_function(&self, name: &'a str) -> Option<&'a Function> {
		match self.functions.get(&name) {
			Some(v) => Some(&***v),
			None => None,
		}
	}
}
<|endoftext|>