<commit_before>use std::collections::HashMap;
use graph_match::graph::Graph;
use graph_parser;

pub fn frame_index() -> HashMap<String, (usize, Graph)> {
    let mut index: HashMap<String, (usize, Graph)> = HashMap::new();
    let frames = vec![
        np_v(),
        np_v_np(),
        np_v_np_prep_np(),
        np_v_np_np(),
        np_v_np_lex(),
        np_v_np_prep_np_prep_np(),
        np_v_np_lex_np(),
        np_v_prep_np(),
        np_v_prep_np_np(),
        np_v_prep_np_prep_np(),
        np_v_adv(),
        np_v_adv_lex(),
        np_v_adv_prep_np(),
        lex_v_np_prep_np(),
        lex_v_prep_np_np(),
        prep_np_v_np(),

        copula_np_v_adj(),
        copula_np_v_np(),

        generic_obj(),
        generic_xcomp(),
    ];

    for frame in frames {
        index.insert(frame.0, (frame.1, frame.2));
    }
    return index;
}

fn np_v_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj";
    return (String::from("NP VERB NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_np_lex() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:lex\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:advmod source:1 target:3 label:advmod";
    return (String::from("NP VERB NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:edge identifier:obj source:1 target:0 label:nsubj";
    return (String::from("NP VERB"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// not currently implementable, requires fuzzy list of edge matching
// fn np_v_lex() {
// }

fn np_v_adv() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adv\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:advmod source:1 target:2 label:advmod";
    return (String::from("NP VERB ADV"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_np_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:dobj\n\
                        type:node identifier:xcomp\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:nmod\n\
                        type:edge identifier:xcomp source:1 target:3 label:xcomp";
    return (String::from("NP VERB NP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:nmod\n\
                        type:edge identifier:case source:2 target:3 label:case";
    return (String::from("NP VERB PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_prep_np_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:node identifier:nmod\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:nmod source:1 target:4 label:nmod\n\
                        type:edge identifier:obj source:4 target:2 label:appos\n\
                        type:edge identifier:case source:4 target:3 label:case";
    return (String::from("NP VERB PREP NP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:node identifier:np3\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:nmod source:1 target:4 label:nmod\n\
                        type:edge identifier:case source:4 target:3 label:case";
    return (String::from("NP VERB NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_np_prep_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:nmod1\n\
                        type:node identifier:nmod2\n\
                        type:node identifier:prep1\n\
                        type:node identifier:prep2\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:nmod1 source:1 target:3 label:nmod\n\
                        type:edge identifier:nmod2 source:1 target:4 label:nmod\n\
                        type:edge identifier:case1 source:3 target:5 label:case\n\
                        type:edge identifier:case1 source:4 target:6 label:case";
    return (String::from("NP VERB NP PREP NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// this used a blacklisted relation, advcl, that is not permitted in extract creation
fn np_v_np_lex_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:lex\n\
                        type:node identifier:np2\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:nmod source:1 target:4 label:advcl\n\
                        type:edge identifier:mark source:4 target:3 label:mark";
    return (String::from("NP VERB NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// this requires a more fuzzy match on clausal relations that are assumed not to exist elsewhere
fn np_v_prep_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:node identifier:verb2 pos:VB\n\
                        type:node identifier:prep2\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:nmod source:1 target:2 label:nmod\n\
                        type:edge identifier:case source:2 target:3 label:case\n\
                        type:edge identifier:advcl source:4 target:1 label:advcl\n\
                        type:edge identifier:case source:4 target:5 label:case";
    return (String::from("NP VERB PREP NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_adv_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adv\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:advmod source:1 target:2 label:advmod\n\
                        type:edge identifier:nmod source:1 target:3 label:nmod\n\
                        type:edge identifier:case source:3 target:4 label:case";
    return (String::from("NP VERB ADV PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// lex should be before adv
fn np_v_adv_lex() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:dobj\n\
                        type:node identifier:adv\n\
                        type:node identifier:lex\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:adv source:1 target:3 label:advmod\n\
                        type:edge identifier:lex source:1 target:4 label:advmod";
    return (String::from("NP VERB ADV LEX"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn prep_np_v_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:prep\n\
                        type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:nmod source:2 target:1 label:nmod\n\
                        type:edge identifier:obj source:2 target:3 label:dobj\n\
                        type:edge identifier:case source:1 target:0 label:case";
    return (String::from("PREP NP VERB NP"), 2, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn lex_v_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:lex\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:node identifier:nmod\n\
                        type:edge identifier:expl source:1 target:0 label:expl\n\
                        type:edge identifier:dobj source:1 target:2 label:dobj\n\
                        type:edge identifier:nmod source:1 target:3 label:nmod\n\
                        type:edge identifier:case source:3 target:4 label:case";
    return (String::from("LEX VERB NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// uses generic dependency, this should not expand.
fn lex_v_prep_np_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:lex\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:node identifier:dep\n\
                        type:edge identifier:expl source:1 target:0 label:expl\n\
                        type:edge identifier:nmod source:1 target:2 label:nmod\n\
                        type:edge identifier:case source:2 target:3 label:case\n\
                        type:edge identifier:dep source:2 target:4 label:dep";
    return (String::from("LEX VERB PREP NP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// copula frames
fn copula_np_v_adj() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adj pos:JJ\n\
                        type:edge identifier:cop source:2 target:1 label:cop\n\
                        type:edge identifier:subj source:2 target:0 label:nsubj";
    return (String::from("copula:NP VERB ADJ"), 2, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn copula_np_v_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:dobj pos:NN\n\
                        type:edge identifier:cop source:2 target:1 label:cop\n\
                        type:edge identifier:subj source:2 target:0 label:nsubj";
    return (String::from("copula:NP VERB NP"), 2, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn generic_obj() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj";
    return (String::from("generic:OBJ"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn generic_xcomp() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:xcomp\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:xcomp source:1 target:2 label:xcomp";
    return (String::from("generic:XCOMP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}
<commit_msg>Correct query frame pattern names<commit_after>use std::collections::HashMap;
use graph_match::graph::Graph;
use graph_parser;

pub fn frame_index() -> HashMap<String, (usize, Graph)> {
    let mut index: HashMap<String, (usize, Graph)> = HashMap::new();
    let frames = vec![
        np_v(),
        np_v_np(),
        np_v_np_prep_np(),
        np_v_np_np(),
        np_v_np_lex(),
        np_v_np_prep_np_prep_np(),
        np_v_np_lex_np(),
        np_v_prep_np(),
        np_v_prep_np_np(),
        np_v_prep_np_prep_np(),
        np_v_adv(),
        np_v_adv_lex(),
        np_v_adv_prep_np(),
        lex_v_np_prep_np(),
        lex_v_prep_np_np(),
        prep_np_v_np(),

        copula_np_v_adj(),
        copula_np_v_np(),

        generic_obj(),
        generic_xcomp(),
    ];

    for frame in frames {
        index.insert(frame.0, (frame.1, frame.2));
    }
    return index;
}

fn np_v_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj";
    return (String::from("NP VERB NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_np_lex() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:lex\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:advmod source:1 target:3 label:advmod";
    return (String::from("NP VERB NP LEX"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:edge identifier:obj source:1 target:0 label:nsubj";
    return (String::from("NP VERB"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// not currently implementable, requires fuzzy list of edge matching
// fn np_v_lex() {
// }

fn np_v_adv() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adv\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:advmod source:1 target:2 label:advmod";
    return (String::from("NP VERB ADV"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_np_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:dobj\n\
                        type:node identifier:xcomp\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:nmod\n\
                        type:edge identifier:xcomp source:1 target:3 label:xcomp";
    return (String::from("NP VERB NP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:nmod\n\
                        type:edge identifier:case source:2 target:3 label:case";
    return (String::from("NP VERB PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_prep_np_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:node identifier:nmod\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:nmod source:1 target:4 label:nmod\n\
                        type:edge identifier:obj source:4 target:2 label:appos\n\
                        type:edge identifier:case source:4 target:3 label:case";
    return (String::from("NP VERB PREP NP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:node identifier:np3\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:nmod source:1 target:4 label:nmod\n\
                        type:edge identifier:case source:4 target:3 label:case";
    return (String::from("NP VERB NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_np_prep_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:nmod1\n\
                        type:node identifier:nmod2\n\
                        type:node identifier:prep1\n\
                        type:node identifier:prep2\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:nmod1 source:1 target:3 label:nmod\n\
                        type:edge identifier:nmod2 source:1 target:4 label:nmod\n\
                        type:edge identifier:case1 source:3 target:5 label:case\n\
                        type:edge identifier:case1 source:4 target:6 label:case";
    return (String::from("NP VERB NP PREP NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// this used a blacklisted relation, advcl, that is not permitted in extract creation
fn np_v_np_lex_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:lex\n\
                        type:node identifier:np2\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:nmod source:1 target:4 label:advcl\n\
                        type:edge identifier:mark source:4 target:3 label:mark";
    return (String::from("NP VERB NP LEX NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// this requires a more fuzzy match on clausal relations that are assumed not to exist elsewhere
fn np_v_prep_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:node identifier:verb2 pos:VB\n\
                        type:node identifier:prep2\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:nmod source:1 target:2 label:nmod\n\
                        type:edge identifier:case source:2 target:3 label:case\n\
                        type:edge identifier:advcl source:4 target:1 label:advcl\n\
                        type:edge identifier:case source:4 target:5 label:case";
    return (String::from("NP VERB PREP NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_adv_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adv\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:advmod source:1 target:2 label:advmod\n\
                        type:edge identifier:nmod source:1 target:3 label:nmod\n\
                        type:edge identifier:case source:3 target:4 label:case";
    return (String::from("NP VERB ADV PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// lex should be before adv
fn np_v_adv_lex() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:dobj\n\
                        type:node identifier:adv\n\
                        type:node identifier:lex\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:adv source:1 target:3 label:advmod\n\
                        type:edge identifier:lex source:1 target:4 label:advmod";
    return (String::from("NP VERB ADV LEX"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn prep_np_v_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:prep\n\
                        type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:nmod source:2 target:1 label:nmod\n\
                        type:edge identifier:obj source:2 target:3 label:dobj\n\
                        type:edge identifier:case source:1 target:0 label:case";
    return (String::from("PREP NP VERB NP"), 2, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn lex_v_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:lex\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:node identifier:nmod\n\
                        type:edge identifier:expl source:1 target:0 label:expl\n\
                        type:edge identifier:dobj source:1 target:2 label:dobj\n\
                        type:edge identifier:nmod source:1 target:3 label:nmod\n\
                        type:edge identifier:case source:3 target:4 label:case";
    return (String::from("LEX VERB NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// uses generic dependency, this should not expand.
fn lex_v_prep_np_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:lex\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:node identifier:dep\n\
                        type:edge identifier:expl source:1 target:0 label:expl\n\
                        type:edge identifier:nmod source:1 target:2 label:nmod\n\
                        type:edge identifier:case source:2 target:3 label:case\n\
                        type:edge identifier:dep source:2 target:4 label:dep";
    return (String::from("LEX VERB PREP NP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// copula frames
fn copula_np_v_adj() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adj pos:JJ\n\
                        type:edge identifier:cop source:2 target:1 label:cop\n\
                        type:edge identifier:subj source:2 target:0 label:nsubj";
    return (String::from("copula:NP VERB ADJ"), 2, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn copula_np_v_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:dobj pos:NN\n\
                        type:edge identifier:cop source:2 target:1 label:cop\n\
                        type:edge identifier:subj source:2 target:0 label:nsubj";
    return (String::from("copula:NP VERB NP"), 2, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn generic_obj() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj";
    return (String::from("generic:OBJ"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn generic_xcomp() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:xcomp\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:xcomp source:1 target:2 label:xcomp";
    return (String::from("generic:XCOMP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Ben Ashford
 *
 * 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.
 */

//! Implementation of ElasticSearch [aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html)

use std::collections::{BTreeMap, HashMap};

use rustc_serialize::json::{Json, ToJson};

use error::EsError;
use units::JsonVal;

/// Script attributes for various attributes
pub struct Script<'a> {
    field:  &'a str,
    script: &'a str,
    params: Option<Json>
}

impl<'a> Script<'a> {
    fn add_to_object(&self, obj: &mut BTreeMap<String, Json>) {
        obj.insert("field".to_owned(), self.field.to_json());
        obj.insert("script".to_owned(), self.script.to_json());
        match self.params {
            Some(ref json) => {
                obj.insert("params".to_owned(), json.clone());
            },
            None           => ()
        }
    }

    pub fn with_params(mut self, params: Json) -> Self {
        self.params = Some(params);
        self
    }
}

/// Min aggregation
pub enum Min<'a> {
    /// Field
    Field(&'a str),

    /// By Script
    Script(Script<'a>)
}

impl<'a> From<Min<'a>> for Aggregation<'a> {
    fn from(from: Min<'a>) -> Aggregation<'a> {
        Aggregation::Metrics(MetricsAggregation::Min(from))
    }
}

impl<'a> ToJson for Min<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self {
            &Min::Field(field) => {
                d.insert("field".to_string(), field.to_json());
            },
            &Min::Script(ref script) => {
                script.add_to_object(&mut d);
            }
        }
        Json::Object(d)
    }
}

/// Individual aggregations and their options
enum MetricsAggregation<'a> {
    Min(Min<'a>)
}

impl<'a> ToJson for MetricsAggregation<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self {
            &MetricsAggregation::Min(ref min_agg) => {
                d.insert("min".to_owned(), min_agg.to_json());
            }
        }
        Json::Object(d)
    }
}

/// Order - used for some bucketing aggregations to determine the order of
/// buckets
pub enum OrderKey<'a> {
    Count,
    Term,
    Expr(&'a str)
}

impl<'a> From<&'a str> for OrderKey<'a> {
    fn from(from: &'a str) -> OrderKey<'a> {
        OrderKey::Expr(from)
    }
}

impl<'a> ToString for OrderKey<'a> {
    fn to_string(&self) -> String {
        match *self {
            OrderKey::Count   => "_count".to_owned(),
            OrderKey::Term    => "_term".to_owned(),
            OrderKey::Expr(e) => e.to_owned()
        }
    }
}

pub struct Order<'a>(OrderKey<'a>, super::Order);

impl<'a> Order<'a> {
    fn asc<O: Into<OrderKey<'a>>>(key: O) -> Order<'a> {
        Order(key.into(), super::Order::Asc)
    }

    fn desc<O: Into<OrderKey<'a>>>(key: O) -> Order<'a> {
        Order(key.into(), super::Order::Desc)
    }
}

impl<'a> ToJson for Order<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert(self.0.to_string(), self.1.to_json());
        Json::Object(d)
    }
}

/// Add to JSON trait
trait AddToJson {
    fn add_to_json(&self, &mut BTreeMap<String, Json>);
}

/// Terms aggregation
pub struct Terms<'a> {
    field:      &'a str,
    size:       Option<u64>,
    shard_size: Option<u64>,
    order:      Option<Order<'a>>
}

impl<'a> Terms<'a> {
    pub fn new(field: &'a str) -> Terms<'a> {
        Terms {
            field:      field,
            size:       None,
            shard_size: None,
            order:      None
        }
    }

    add_field!(with_size, size, u64);
    add_field!(with_shard_size, shard_size, u64);
    add_field!(with_order, order, Order<'a>);
}

impl<'a> From<(Terms<'a>, Aggregations<'a>)> for Aggregation<'a> {
    fn from(from: (Terms<'a>, Aggregations<'a>)) -> Aggregation<'a> {
        Aggregation::Bucket(BucketAggregation::Terms(from.0), Some(from.1))
    }
}

impl<'a> From<Terms<'a>> for Aggregation<'a> {
    fn from(from: Terms<'a>) -> Aggregation<'a> {
        Aggregation::Bucket(BucketAggregation::Terms(from), None)
    }
}

impl<'a> ToJson for Terms<'a> {
    fn to_json(&self) -> Json {
        let mut json = BTreeMap::new();
        json.insert("field".to_owned(), Json::String(self.field.to_owned()));
        optional_add!(json, self.size, "size");
        optional_add!(json, self.shard_size, "shard_size");
        optional_add!(json, self.order, "order");
        Json::Object(json)
    }
}

/// The set of bucket aggregations
enum BucketAggregation<'a> {
    Terms(Terms<'a>)
}

impl<'a> AddToJson for BucketAggregation<'a> {
    fn add_to_json(&self, json: &mut BTreeMap<String, Json>) {
        match self {
            &BucketAggregation::Terms(ref terms) => {
                json.insert("terms".to_owned(), terms.to_json());
            }
        }
    }
}

/// Aggregations are either metrics or bucket-based aggregations
enum Aggregation<'a> {
    /// A metric aggregation (e.g. min)
    Metrics(MetricsAggregation<'a>),

    /// A bucket aggregation, groups data into buckets and optionally applies
    /// sub-aggregations
    Bucket(BucketAggregation<'a>, Option<Aggregations<'a>>)
}

impl<'a> ToJson for Aggregation<'a> {
    fn to_json(&self) -> Json {
        match self {
            &Aggregation::Metrics(ref ma)          => {
                ma.to_json()
            },
            &Aggregation::Bucket(ref ba, ref aggs) => {
                let mut d = BTreeMap::new();
                ba.add_to_json(&mut d);
                match aggs {
                    &Some(ref a) => {
                        d.insert("aggs".to_owned(), a.to_json());
                    },
                    &None        => ()
                }
                Json::Object(d)
            }
        }
    }
}

/// The set of aggregations
pub struct Aggregations<'a>(HashMap<&'a str, Aggregation<'a>>);

impl<'a> Aggregations<'a> {
    pub fn new() -> Aggregations<'a> {
        Aggregations(HashMap::new())
    }

    pub fn insert<A: Into<Aggregation<'a>>>(&mut self, key: &'a str, val: A) {
        self.0.insert(key, val.into());
    }
}

impl<'a> ToJson for Aggregations<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        for (k, ref v) in self.0.iter() {
            d.insert((*k).to_owned(), v.to_json());
        }
        Json::Object(d)
    }
}

// Result objects

// Metrics result

#[derive(Debug)]
pub struct MinResult {
    pub value: JsonVal
}

impl<'a> From<&'a Json> for MinResult {
    fn from(from: &'a Json) -> MinResult {
        MinResult {
            value: JsonVal::from(from.find("value").expect("No 'value' value"))
        }
    }
}

// Buckets result

#[derive(Debug)]
pub struct TermsBucketResult {
    pub key: JsonVal,
    pub doc_count: u64,
    pub aggs: Option<AggregationsResult>
}

impl TermsBucketResult {
    fn from(from: &Json, aggs: &Option<Aggregations>) -> TermsBucketResult {
        TermsBucketResult {
            key: JsonVal::from(from.find("key").expect("No 'key' value")),
            doc_count: get_json_u64!(from, "doc_count"),
            aggs: match aggs {
                &Some(ref agg) => {
                    Some(object_to_result(agg,
                                          get_json_object!(from, "aggregations")))
                },
                &None          => None
            }
        }
    }
}

#[derive(Debug)]
pub struct TermsResult {
    pub doc_count_error_upper_bound: u64,
    pub sum_other_doc_count: u64,
    pub buckets: Vec<TermsBucketResult>
}

impl TermsResult {
    fn from(from: &Json, aggs: &Option<Aggregations>) -> TermsResult {
        TermsResult {
            doc_count_error_upper_bound: get_json_u64!(from, "doc_count_error_upper_bound"),
            sum_other_doc_count: get_json_u64!(from, "sum_other_doc_count"),
            buckets: from.find("buckets").expect("No buckets")
                .as_array().expect("Not an array")
                .iter().map(|bucket| {
                    TermsBucketResult::from(bucket, aggs)
                }).collect()
        }
    }
}

/// The result of one specific aggregation
///
/// The data returned varies depending on aggregation type
#[derive(Debug)]
pub enum AggregationResult {
    // Metrics
    Min(MinResult),

    // Buckets
    Terms(TermsResult)
}

impl AggregationResult {
    pub fn as_min<'a>(&'a self) -> Result<&'a MinResult, EsError> {
        use self::AggregationResult::*;
        match self {
            &Min(ref res) => Ok(res),
            _             => Err(EsError::EsError(format!("Wrong type: {:?}", self)))
        }
    }
}

#[derive(Debug)]
pub struct AggregationsResult(HashMap<String, AggregationResult>);

/// Loads a Json object of aggregation results into an `AggregationsResult`.
fn object_to_result(aggs: &Aggregations, object: &BTreeMap<String, Json>) -> AggregationsResult {
    let mut ar_map = HashMap::new();

    for (key, val) in aggs.0.iter() {
        let owned_key = (*key).to_owned();
        let json = object.get(&owned_key).expect(&format!("No key: {}", &owned_key));
        ar_map.insert(owned_key, match val {
            &Aggregation::Metrics(ref ma) => {
                match ma {
                    &MetricsAggregation::Min(_) => {
                        AggregationResult::Min(MinResult::from(json))
                    }
                }
            },
            &Aggregation::Bucket(ref ba, ref aggs) => {
                match ba {
                    &BucketAggregation::Terms(_) => {
                        AggregationResult::Terms(TermsResult::from(json, aggs))
                    }
                }
            }
        });
    }

    info!("Processed aggs - From: {:?}. To: {:?}", object, ar_map);

    AggregationsResult(ar_map)
}

impl AggregationsResult {
    pub fn get<'a>(&'a self, key: &str) -> Result<&'a AggregationResult, EsError> {
        match self.0.get(key) {
            Some(ref agg_res) => Ok(agg_res),
            None              => Err(EsError::EsError(format!("No agg for key: {}",
                                                              key)))
        }
    }

    pub fn from(aggs: &Aggregations, json: &Json) -> AggregationsResult {
        let object = json.find("aggregations")
            .expect("No aggregations")
            .as_object()
            .expect("No aggregations");

        object_to_result(aggs, object)
    }
}
<commit_msg>Drying, fixing and commenting<commit_after>/*
 * Copyright 2015 Ben Ashford
 *
 * 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.
 */

//! Implementation of ElasticSearch [aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html)

use std::collections::{BTreeMap, HashMap};

use rustc_serialize::json::{Json, ToJson};

use error::EsError;
use units::JsonVal;

/// Script attributes for various attributes
pub struct Script<'a> {
    field:  &'a str,
    script: &'a str,
    params: Option<Json>
}

impl<'a> Script<'a> {
    fn add_to_object(&self, obj: &mut BTreeMap<String, Json>) {
        obj.insert("field".to_owned(), self.field.to_json());
        obj.insert("script".to_owned(), self.script.to_json());
        match self.params {
            Some(ref json) => {
                obj.insert("params".to_owned(), json.clone());
            },
            None           => ()
        }
    }

    pub fn with_params(mut self, params: Json) -> Self {
        self.params = Some(params);
        self
    }
}

/// Min aggregation
pub enum Min<'a> {
    /// Field
    Field(&'a str),

    /// By Script
    Script(Script<'a>)
}

impl<'a> From<Min<'a>> for Aggregation<'a> {
    fn from(from: Min<'a>) -> Aggregation<'a> {
        Aggregation::Metrics(MetricsAggregation::Min(from))
    }
}

impl<'a> ToJson for Min<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self {
            &Min::Field(field) => {
                d.insert("field".to_string(), field.to_json());
            },
            &Min::Script(ref script) => {
                script.add_to_object(&mut d);
            }
        }
        Json::Object(d)
    }
}

/// Individual aggregations and their options
enum MetricsAggregation<'a> {
    Min(Min<'a>)
}

impl<'a> ToJson for MetricsAggregation<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        match self {
            &MetricsAggregation::Min(ref min_agg) => {
                d.insert("min".to_owned(), min_agg.to_json());
            }
        }
        Json::Object(d)
    }
}

/// Order - used for some bucketing aggregations to determine the order of
/// buckets
pub enum OrderKey<'a> {
    Count,
    Term,
    Expr(&'a str)
}

impl<'a> From<&'a str> for OrderKey<'a> {
    fn from(from: &'a str) -> OrderKey<'a> {
        OrderKey::Expr(from)
    }
}

impl<'a> ToString for OrderKey<'a> {
    fn to_string(&self) -> String {
        match *self {
            OrderKey::Count   => "_count".to_owned(),
            OrderKey::Term    => "_term".to_owned(),
            OrderKey::Expr(e) => e.to_owned()
        }
    }
}

/// Used to define the ordering of buckets in a some bucketted aggregations
///
/// # Examples
///
/// ```
/// use rs_es::operations::search::aggregations::{Order, OrderKey};
///
/// let order1 = Order::asc(OrderKey::Count);
/// let order2 = Order::desc("field_name");
/// ```
///
/// The first will produce a JSON fragment: `{"_count": "asc"}`; the second will
/// produce a JSON fragment: `{"field_name", "desc"}`
pub struct Order<'a>(OrderKey<'a>, super::Order);

impl<'a> Order<'a> {
    /// Create an `Order` ascending
    pub fn asc<O: Into<OrderKey<'a>>>(key: O) -> Order<'a> {
        Order(key.into(), super::Order::Asc)
    }

    /// Create an `Order` descending
    pub fn desc<O: Into<OrderKey<'a>>>(key: O) -> Order<'a> {
        Order(key.into(), super::Order::Desc)
    }
}

impl<'a> ToJson for Order<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert(self.0.to_string(), self.1.to_json());
        Json::Object(d)
    }
}

/// Add to JSON trait
trait AddToJson {
    fn add_to_json(&self, &mut BTreeMap<String, Json>);
}

/// Terms aggregation
pub struct Terms<'a> {
    field:      &'a str,
    size:       Option<u64>,
    shard_size: Option<u64>,
    order:      Option<Order<'a>>
}

impl<'a> Terms<'a> {
    pub fn new(field: &'a str) -> Terms<'a> {
        Terms {
            field:      field,
            size:       None,
            shard_size: None,
            order:      None
        }
    }

    add_field!(with_size, size, u64);
    add_field!(with_shard_size, shard_size, u64);
    add_field!(with_order, order, Order<'a>);
}

impl<'a> From<(Terms<'a>, Aggregations<'a>)> for Aggregation<'a> {
    fn from(from: (Terms<'a>, Aggregations<'a>)) -> Aggregation<'a> {
        Aggregation::Bucket(BucketAggregation::Terms(from.0), Some(from.1))
    }
}

impl<'a> From<Terms<'a>> for Aggregation<'a> {
    fn from(from: Terms<'a>) -> Aggregation<'a> {
        Aggregation::Bucket(BucketAggregation::Terms(from), None)
    }
}

impl<'a> ToJson for Terms<'a> {
    fn to_json(&self) -> Json {
        let mut json = BTreeMap::new();
        json.insert("field".to_owned(), Json::String(self.field.to_owned()));
        optional_add!(json, self.size, "size");
        optional_add!(json, self.shard_size, "shard_size");
        optional_add!(json, self.order, "order");
        Json::Object(json)
    }
}

/// The set of bucket aggregations
enum BucketAggregation<'a> {
    Terms(Terms<'a>)
}

impl<'a> AddToJson for BucketAggregation<'a> {
    fn add_to_json(&self, json: &mut BTreeMap<String, Json>) {
        match self {
            &BucketAggregation::Terms(ref terms) => {
                json.insert("terms".to_owned(), terms.to_json());
            }
        }
    }
}

/// Aggregations are either metrics or bucket-based aggregations
enum Aggregation<'a> {
    /// A metric aggregation (e.g. min)
    Metrics(MetricsAggregation<'a>),

    /// A bucket aggregation, groups data into buckets and optionally applies
    /// sub-aggregations
    Bucket(BucketAggregation<'a>, Option<Aggregations<'a>>)
}

impl<'a> ToJson for Aggregation<'a> {
    fn to_json(&self) -> Json {
        match self {
            &Aggregation::Metrics(ref ma)          => {
                ma.to_json()
            },
            &Aggregation::Bucket(ref ba, ref aggs) => {
                let mut d = BTreeMap::new();
                ba.add_to_json(&mut d);
                match aggs {
                    &Some(ref a) => {
                        d.insert("aggs".to_owned(), a.to_json());
                    },
                    &None        => ()
                }
                Json::Object(d)
            }
        }
    }
}

/// The set of aggregations
pub struct Aggregations<'a>(HashMap<&'a str, Aggregation<'a>>);

impl<'a> Aggregations<'a> {
    pub fn new() -> Aggregations<'a> {
        Aggregations(HashMap::new())
    }

    pub fn insert<A: Into<Aggregation<'a>>>(&mut self, key: &'a str, val: A) {
        self.0.insert(key, val.into());
    }
}

impl<'a> ToJson for Aggregations<'a> {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        for (k, ref v) in self.0.iter() {
            d.insert((*k).to_owned(), v.to_json());
        }
        Json::Object(d)
    }
}

// Result objects

// Metrics result

#[derive(Debug)]
pub struct MinResult {
    pub value: JsonVal
}

impl<'a> From<&'a Json> for MinResult {
    fn from(from: &'a Json) -> MinResult {
        MinResult {
            value: JsonVal::from(from.find("value").expect("No 'value' value"))
        }
    }
}

// Buckets result

#[derive(Debug)]
pub struct TermsBucketResult {
    pub key: JsonVal,
    pub doc_count: u64,
    pub aggs: Option<AggregationsResult>
}

impl TermsBucketResult {
    fn from(from: &Json, aggs: &Option<Aggregations>) -> TermsBucketResult {
        TermsBucketResult {
            key: JsonVal::from(from.find("key").expect("No 'key' value")),
            doc_count: get_json_u64!(from, "doc_count"),
            aggs: match aggs {
                &Some(ref agg) => {
                    Some(object_to_result(agg,
                                          get_json_object!(from, "aggregations")))
                },
                &None          => None
            }
        }
    }
}

#[derive(Debug)]
pub struct TermsResult {
    pub doc_count_error_upper_bound: u64,
    pub sum_other_doc_count: u64,
    pub buckets: Vec<TermsBucketResult>
}

impl TermsResult {
    fn from(from: &Json, aggs: &Option<Aggregations>) -> TermsResult {
        TermsResult {
            doc_count_error_upper_bound: get_json_u64!(from, "doc_count_error_upper_bound"),
            sum_other_doc_count: get_json_u64!(from, "sum_other_doc_count"),
            buckets: from.find("buckets").expect("No buckets")
                .as_array().expect("Not an array")
                .iter().map(|bucket| {
                    TermsBucketResult::from(bucket, aggs)
                }).collect()
        }
    }
}

/// The result of one specific aggregation
///
/// The data returned varies depending on aggregation type
#[derive(Debug)]
pub enum AggregationResult {
    // Metrics
    Min(MinResult),

    // Buckets
    Terms(TermsResult)
}

/// Macro to implement the various as... functions that return the details of an
/// aggregation for that particular type
macro_rules! agg_as {
    ($n:ident,$t:ident,$rt:ty) => {
        pub fn $n<'a>(&'a self) -> Result<&'a $rt, EsError> {
            match self {
                &AggregationResult::$t(ref res) => Ok(res),
                _                               => {
                    Err(EsError::EsError(format!("Wrong type: {:?}", self)))
                }
            }
        }
    }
}

impl AggregationResult {
    // Metrics
    agg_as!(as_min, Min, MinResult);

    // buckets
    agg_as!(as_terms, Terms, TermsResult);
}

#[derive(Debug)]
pub struct AggregationsResult(HashMap<String, AggregationResult>);

/// Loads a Json object of aggregation results into an `AggregationsResult`.
fn object_to_result(aggs: &Aggregations, object: &BTreeMap<String, Json>) -> AggregationsResult {
    let mut ar_map = HashMap::new();

    for (key, val) in aggs.0.iter() {
        let owned_key = (*key).to_owned();
        let json = object.get(&owned_key).expect(&format!("No key: {}", &owned_key));
        ar_map.insert(owned_key, match val {
            &Aggregation::Metrics(ref ma) => {
                match ma {
                    &MetricsAggregation::Min(_) => {
                        AggregationResult::Min(MinResult::from(json))
                    }
                }
            },
            &Aggregation::Bucket(ref ba, ref aggs) => {
                match ba {
                    &BucketAggregation::Terms(_) => {
                        AggregationResult::Terms(TermsResult::from(json, aggs))
                    }
                }
            }
        });
    }

    info!("Processed aggs - From: {:?}. To: {:?}", object, ar_map);

    AggregationsResult(ar_map)
}

impl AggregationsResult {
    pub fn get<'a>(&'a self, key: &str) -> Result<&'a AggregationResult, EsError> {
        match self.0.get(key) {
            Some(ref agg_res) => Ok(agg_res),
            None              => Err(EsError::EsError(format!("No agg for key: {}",
                                                              key)))
        }
    }

    pub fn from(aggs: &Aggregations, json: &Json) -> AggregationsResult {
        let object = json.find("aggregations")
            .expect("No aggregations")
            .as_object()
            .expect("No aggregations");

        object_to_result(aggs, object)
    }
}
<|endoftext|>


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

use std::os::unix::io::RawFd;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;

use super::*;
use sys_util::{EventFd, GuestMemory};

/// Trait for virtio devices to be driven by a virtio transport.
///
/// The lifecycle of a virtio device is to be moved to a virtio transport, which will then query the
/// device. Once the guest driver has configured the device, `VirtioDevice::activate` will be called
/// and all the events, memory, and queues for device operation will be moved into the device.
/// Optionally, a virtio device can implement device reset in which it returns said resources and
/// resets its internal.
pub trait VirtioDevice: Send {
    /// Returns a label suitable for debug output.
    fn debug_label(&self) -> String {
        match type_to_str(self.device_type()) {
            Some(s) => format!("virtio-{}", s),
            None => format!("virtio (type {})", self.device_type()),
        }
    }

    /// A vector of device-specific file descriptors that must be kept open
    /// after jailing. Must be called before the process is jailed.
    fn keep_fds(&self) -> Vec<RawFd>;

    /// The virtio device type.
    fn device_type(&self) -> u32;

    /// The maximum size of each queue that this device supports.
    fn queue_max_sizes(&self) -> &[u16];

    /// The set of feature bits that this device supports.
    fn features(&self) -> u64 {
        1 << VIRTIO_F_VERSION_1
    }

    /// Acknowledges that this set of features should be enabled.
    fn ack_features(&mut self, value: u64) {
        let _ = value;
    }

    /// Reads this device configuration space at `offset`.
    fn read_config(&self, offset: u64, data: &mut [u8]) {
        let _ = offset;
        let _ = data;
    }

    /// Writes to this device configuration space at `offset`.
    fn write_config(&mut self, offset: u64, data: &[u8]) {
        let _ = offset;
        let _ = data;
    }

    /// Activates this device for real usage.
    fn activate(
        &mut self,
        mem: GuestMemory,
        interrupt_evt: EventFd,
        interrupt_resample_evt: EventFd,
        status: Arc<AtomicUsize>,
        queues: Vec<Queue>,
        queue_evts: Vec<EventFd>,
    );

    /// Optionally deactivates this device and returns ownership of the guest memory map, interrupt
    /// event, and queue events.
    fn reset(&mut self) -> Option<(EventFd, Vec<EventFd>)> {
        None
    }
}
<commit_msg>devices: virtio: add PCI configuration callback function<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::os::unix::io::RawFd;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;

use super::*;
use pci::PciBarConfiguration;
use sys_util::{EventFd, GuestMemory};

/// Trait for virtio devices to be driven by a virtio transport.
///
/// The lifecycle of a virtio device is to be moved to a virtio transport, which will then query the
/// device. Once the guest driver has configured the device, `VirtioDevice::activate` will be called
/// and all the events, memory, and queues for device operation will be moved into the device.
/// Optionally, a virtio device can implement device reset in which it returns said resources and
/// resets its internal.
pub trait VirtioDevice: Send {
    /// Returns a label suitable for debug output.
    fn debug_label(&self) -> String {
        match type_to_str(self.device_type()) {
            Some(s) => format!("virtio-{}", s),
            None => format!("virtio (type {})", self.device_type()),
        }
    }

    /// A vector of device-specific file descriptors that must be kept open
    /// after jailing. Must be called before the process is jailed.
    fn keep_fds(&self) -> Vec<RawFd>;

    /// The virtio device type.
    fn device_type(&self) -> u32;

    /// The maximum size of each queue that this device supports.
    fn queue_max_sizes(&self) -> &[u16];

    /// The set of feature bits that this device supports.
    fn features(&self) -> u64 {
        1 << VIRTIO_F_VERSION_1
    }

    /// Acknowledges that this set of features should be enabled.
    fn ack_features(&mut self, value: u64) {
        let _ = value;
    }

    /// Reads this device configuration space at `offset`.
    fn read_config(&self, offset: u64, data: &mut [u8]) {
        let _ = offset;
        let _ = data;
    }

    /// Writes to this device configuration space at `offset`.
    fn write_config(&mut self, offset: u64, data: &[u8]) {
        let _ = offset;
        let _ = data;
    }

    /// Activates this device for real usage.
    fn activate(
        &mut self,
        mem: GuestMemory,
        interrupt_evt: EventFd,
        interrupt_resample_evt: EventFd,
        status: Arc<AtomicUsize>,
        queues: Vec<Queue>,
        queue_evts: Vec<EventFd>,
    );

    /// Optionally deactivates this device and returns ownership of the guest memory map, interrupt
    /// event, and queue events.
    fn reset(&mut self) -> Option<(EventFd, Vec<EventFd>)> {
        None
    }

    /// Optionally returns additional BAR configuration needed by device
    fn get_device_bars(&self) -> Option<Vec<PciBarConfiguration>> {
        None
    }
}
<|endoftext|>


<commit_before>use super::*;
use crate::{structs::*, properties::PropertySource};

#[test]
fn test_contains() {
    let rect = Bounds(Rect::new(5.0, 8.0, 100.0, 80.0));
    let inner_point = Point::new(50.0, 50.0);
    let outer_point_one = Point::new(0.0, 0.0);
    let outer_point_two = Point::new(106.0, 80.0);

    assert!(rect.contains((inner_point.x, inner_point.y)));
    assert!(!rect.contains((outer_point_one.x, outer_point_one.y)));
    assert!(!rect.contains((outer_point_two.x, outer_point_two.y)));

    let neg_rect = Bounds(Rect::new(-5.0, -8.0, 100.0, 80.0));
    let neg_inner_point = Point::new(-3.0, -6.0);
    let neg_outer_point_one = Point::new(-10.0, -8.0);
    let neg_outer_point_two = Point::new(-5.0, 80.0);

    assert!(neg_rect.contains((neg_inner_point.x, neg_inner_point.y)));
    assert!(!neg_rect.contains((neg_outer_point_one.x, neg_outer_point_one.y)));
    assert!(!neg_rect.contains((neg_outer_point_two.x, neg_outer_point_two.y)));
}

#[test]
fn test_contains_rect() {
    let rect = Bounds(Rect::new(5.0, 8.0, 100.0, 80.0));
    let inner_rect = Bounds(Rect::new(10.0, 12.0, 20.0, 20.0));
    let outer_rect_one = Bounds(Rect::new(0.0, 0.0, 2.0, 3.0));
    let outer_rect_two = Bounds(Rect::new(105.0, 89.0, 100.0, 50.0));

    assert!(rect.contains_rect(&inner_rect));
    assert!(!rect.contains_rect(&outer_rect_one));
    assert!(!rect.contains_rect(&outer_rect_two));

    let neg_rect = Bounds(Rect::new(-5.0, -8.0, 100.0, 80.0));
    let inner_neg_rect = Bounds(Rect::new(-2.0, -6.0, 20.0, 20.0));
    let outer_neg_rect_one = Bounds(Rect::new(-30.0, -20.0, 2.0, 3.0));
    let outer_neg_rect_two = Bounds(Rect::new(105.0, 89.0, 100.0, 50.0));

    assert!(neg_rect.contains_rect(&inner_neg_rect));
    assert!(!neg_rect.contains_rect(&outer_neg_rect_one));
    assert!(!neg_rect.contains_rect(&outer_neg_rect_two));
}

#[test]
fn test_intersects() {
    let rect = Bounds(Rect::new(5.0, 8.0, 100.0, 80.0));
    let inner_rect = Bounds(Rect::new(2.0, 6.0, 100.0, 20.0));
    let outer_rect_one = Bounds(Rect::new(0.0, 0.0, 2.0, 3.0));
    let outer_rect_two = Bounds(Rect::new(105.0, 89.0, 100.0, 50.0));

    assert!(rect.intersects(&inner_rect));
    assert!(!rect.intersects(&outer_rect_one));
    assert!(!rect.intersects(&outer_rect_two));

    let neg_rect = Bounds(Rect::new(-5.0, -8.0, 100.0, 80.0));
    let inner_neg_rect = Bounds(Rect::new(-2.0, -6.0, 100.0, 120.0));
    let outer_neg_rect_one = Bounds(Rect::new(-30.0, -20.0, 2.0, 3.0));
    let outer_neg_rect_two = Bounds(Rect::new(105.0, 89.0, 100.0, 50.0));

    assert!(neg_rect.intersects(&inner_neg_rect));
    assert!(!neg_rect.intersects(&outer_neg_rect_one));
    assert!(!neg_rect.intersects(&outer_neg_rect_two));
}

#[test]
fn test_set_width() {
    let mut bounds = Bounds::default();
    bounds.set_width(5.0);

    assert_eq!(5.0, bounds.width());
}

#[test]
fn test_set_height() {
    let mut bounds = Bounds::default();
    bounds.set_height(5.0);

    assert_eq!(5.0, bounds.height());
}

#[test]
fn test_set_size() {
    let mut bounds = Bounds::default();
    bounds.set_size(6.0, 7.0);

    assert_eq!(6.0, bounds.width());
    assert_eq!(7.0, bounds.height());
}

#[test]
fn test_set_x() {
    let mut bounds = Bounds::default();
    bounds.set_x(5.0);

    assert_eq!(5.0, bounds.x());
}

#[test]
fn test_set_y() {
    let mut bounds = Bounds::default();
    bounds.set_y(5.0);

    assert_eq!(5.0, bounds.y());
}

#[test]
fn test_set_position() {
    let mut bounds = Bounds::default();
    bounds.set_position(6.0, 7.0);

    assert_eq!(6.0, bounds.x());
    assert_eq!(7.0, bounds.y());
}

#[test]
fn test_from() {
    let bounds = Bounds::from((9.0, 10.0, 11.0, 12.0));

    assert_eq!(9.0, bounds.x());
    assert_eq!(10.0, bounds.y());
    assert_eq!(11.0, bounds.width());
    assert_eq!(12.0, bounds.height());
}

#[test]
fn test_into() {
     let bounds: PropertySource<Bounds> = (17.0, 18.0, 19.0, 20.0).into();

     assert_eq!(bounds, PropertySource::<Bounds>::Value(Bounds(Rect::new(17.0, 18.0, 19.0, 20.0))));
}<commit_msg>:ambulance: Fix a broken test<commit_after>use super::*;
use crate::{structs::*, properties::PropertySource};

#[test]
fn test_contains() {
    let rect = Bounds(Rect::new(5.0, 8.0, 100.0, 80.0));
    let inner_point = Point::new(50.0, 50.0);
    let outer_point_one = Point::new(0.0, 0.0);
    let outer_point_two = Point::new(106.0, 80.0);

    assert!(rect.contains((inner_point.x, inner_point.y)));
    assert!(!rect.contains((outer_point_one.x, outer_point_one.y)));
    assert!(!rect.contains((outer_point_two.x, outer_point_two.y)));

    let neg_rect = Bounds(Rect::new(-5.0, -8.0, 100.0, 80.0));
    let neg_inner_point = Point::new(-3.0, -6.0);
    let neg_outer_point_one = Point::new(-10.0, -8.0);
    let neg_outer_point_two = Point::new(-5.0, 80.0);

    assert!(neg_rect.contains((neg_inner_point.x, neg_inner_point.y)));
    assert!(!neg_rect.contains((neg_outer_point_one.x, neg_outer_point_one.y)));
    assert!(!neg_rect.contains((neg_outer_point_two.x, neg_outer_point_two.y)));
}

#[test]
fn test_contains_rect() {
    let rect = Bounds(Rect::new(5.0, 8.0, 100.0, 80.0));
    let inner_rect = Bounds(Rect::new(10.0, 12.0, 20.0, 20.0));
    let outer_rect_one = Bounds(Rect::new(0.0, 0.0, 2.0, 3.0));
    let outer_rect_two = Bounds(Rect::new(105.0, 89.0, 100.0, 50.0));

    assert!(rect.contains_rect(&inner_rect));
    assert!(!rect.contains_rect(&outer_rect_one));
    assert!(!rect.contains_rect(&outer_rect_two));

    let neg_rect = Bounds(Rect::new(-5.0, -8.0, 100.0, 80.0));
    let inner_neg_rect = Bounds(Rect::new(-2.0, -6.0, 20.0, 20.0));
    let outer_neg_rect_one = Bounds(Rect::new(-30.0, -20.0, 2.0, 3.0));
    let outer_neg_rect_two = Bounds(Rect::new(105.0, 89.0, 100.0, 50.0));

    assert!(neg_rect.contains_rect(&inner_neg_rect));
    assert!(!neg_rect.contains_rect(&outer_neg_rect_one));
    assert!(!neg_rect.contains_rect(&outer_neg_rect_two));
}

#[test]
fn test_intersects() {
    let rect = Bounds(Rect::new(5.0, 8.0, 100.0, 80.0));
    let inner_rect = Bounds(Rect::new(2.0, 6.0, 100.0, 20.0));
    let outer_rect_one = Bounds(Rect::new(0.0, 0.0, 2.0, 3.0));
    let outer_rect_two = Bounds(Rect::new(105.0, 89.0, 100.0, 50.0));

    assert!(rect.intersects(&inner_rect));
    assert!(!rect.intersects(&outer_rect_one));
    assert!(!rect.intersects(&outer_rect_two));

    let neg_rect = Bounds(Rect::new(-5.0, -8.0, 100.0, 80.0));
    let inner_neg_rect = Bounds(Rect::new(-2.0, -6.0, 100.0, 120.0));
    let outer_neg_rect_one = Bounds(Rect::new(-30.0, -20.0, 2.0, 3.0));
    let outer_neg_rect_two = Bounds(Rect::new(105.0, 89.0, 100.0, 50.0));

    assert!(neg_rect.intersects(&inner_neg_rect));
    assert!(!neg_rect.intersects(&outer_neg_rect_one));
    assert!(!neg_rect.intersects(&outer_neg_rect_two));
}

#[test]
fn test_set_width() {
    let mut bounds = Bounds::default();
    bounds.set_width(5.0);

    assert_eq!(5.0, bounds.width());
}

#[test]
fn test_set_height() {
    let mut bounds = Bounds::default();
    bounds.set_height(5.0);

    assert_eq!(5.0, bounds.height());
}

#[test]
fn test_set_size() {
    let mut bounds = Bounds::default();
    bounds.set_size(6.0, 7.0);

    assert_eq!(6.0, bounds.width());
    assert_eq!(7.0, bounds.height());
}

#[test]
fn test_set_x() {
    let mut bounds = Bounds::default();
    bounds.set_x(5.0);

    assert_eq!(5.0, bounds.x());
}

#[test]
fn test_set_y() {
    let mut bounds = Bounds::default();
    bounds.set_y(5.0);

    assert_eq!(5.0, bounds.y());
}

#[test]
fn test_set_position() {
    let mut bounds = Bounds::default();
    bounds.set_position(6.0, 7.0);

    assert_eq!(6.0, bounds.x());
    assert_eq!(7.0, bounds.y());
}

#[test]
fn test_from() {
    let bounds = Bounds::from((9.0, 10.0, 11.0, 12.0));

    assert_eq!(9.0, bounds.x());
    assert_eq!(10.0, bounds.y());
    assert_eq!(11.0, bounds.width());
    assert_eq!(12.0, bounds.height());
}

#[test]
fn test_into() {
     let bounds: PropertySource<Bounds> = (17.0, 18.0, 19.0, 20.0).into();

     assert_eq!(bounds, PropertySource::Value::<Bounds>(Bounds(Rect::new(17.0, 18.0, 19.0, 20.0))));
}
<|endoftext|>


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

use util::worker::Runnable;
use util::rocksdb;

use rocksdb::DB;
use std::sync::Arc;
use std::fmt::{self, Formatter, Display};
use std::error;
use super::metrics::COMPACT_RANGE_CF;

pub struct Task {
    pub cf_name: String,
    pub start_key: Option<Vec<u8>>, // None means smallest key
    pub end_key: Option<Vec<u8>>, // None means largest key
}

impl Display for Task {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f,
               "Compact CF[{}], range[{:?}, {:?}]",
               self.cf_name,
               self.start_key,
               self.end_key)
    }
}

quick_error! {
    #[derive(Debug)]
    enum Error {
        Other(err: Box<error::Error + Sync + Send>) {
            from()
            cause(err.as_ref())
            description(err.description())
            display("compact failed {:?}", err)
        }
    }
}

pub struct Runner {
    engine: Arc<DB>,
}

impl Runner {
    pub fn new(engine: Arc<DB>) -> Runner {
        Runner { engine: engine }
    }

    fn compact_range_cf(&mut self,
                        cf_name: String,
                        start_key: Option<Vec<u8>>,
                        end_key: Option<Vec<u8>>)
                        -> Result<(), Error> {
        let cf_handle = box_try!(rocksdb::get_cf_handle(&self.engine, &cf_name));
        let compact_range_timer = COMPACT_RANGE_CF.with_label_values(&[&cf_name])
            .start_timer();
        self.engine.compact_range_cf(cf_handle,
                                     start_key.as_ref().map(Vec::as_slice),
                                     end_key.as_ref().map(Vec::as_slice));

        compact_range_timer.observe_duration();
        Ok(())
    }
}

impl Runnable<Task> for Runner {
    fn run(&mut self, task: Task) {
        let cf = task.cf_name.clone();
        if let Err(e) = self.compact_range_cf(task.cf_name, task.start_key, task.end_key) {
            error!("execute compact range for cf {} failed, err {}", &cf, e);
        } else {
            info!("compact range for cf {} finished", &cf);
        }
    }
}
<commit_msg>escape log (#1264)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use util::worker::Runnable;
use util::rocksdb;
use util::escape;

use rocksdb::DB;
use std::sync::Arc;
use std::fmt::{self, Formatter, Display};
use std::error;
use super::metrics::COMPACT_RANGE_CF;

pub struct Task {
    pub cf_name: String,
    pub start_key: Option<Vec<u8>>, // None means smallest key
    pub end_key: Option<Vec<u8>>, // None means largest key
}

impl Display for Task {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f,
               "Compact CF[{}], range[{:?}, {:?}]",
               self.cf_name,
               self.start_key.as_ref().map(|k| escape(&k)),
               self.end_key.as_ref().map(|k| escape(&k)))
    }
}

quick_error! {
    #[derive(Debug)]
    enum Error {
        Other(err: Box<error::Error + Sync + Send>) {
            from()
            cause(err.as_ref())
            description(err.description())
            display("compact failed {:?}", err)
        }
    }
}

pub struct Runner {
    engine: Arc<DB>,
}

impl Runner {
    pub fn new(engine: Arc<DB>) -> Runner {
        Runner { engine: engine }
    }

    fn compact_range_cf(&mut self,
                        cf_name: String,
                        start_key: Option<Vec<u8>>,
                        end_key: Option<Vec<u8>>)
                        -> Result<(), Error> {
        let cf_handle = box_try!(rocksdb::get_cf_handle(&self.engine, &cf_name));
        let compact_range_timer = COMPACT_RANGE_CF.with_label_values(&[&cf_name])
            .start_timer();
        self.engine.compact_range_cf(cf_handle,
                                     start_key.as_ref().map(Vec::as_slice),
                                     end_key.as_ref().map(Vec::as_slice));

        compact_range_timer.observe_duration();
        Ok(())
    }
}

impl Runnable<Task> for Runner {
    fn run(&mut self, task: Task) {
        let cf = task.cf_name.clone();
        if let Err(e) = self.compact_range_cf(task.cf_name, task.start_key, task.end_key) {
            error!("execute compact range for cf {} failed, err {}", &cf, e);
        } else {
            info!("compact range for cf {} finished", &cf);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 TiKV Project Authors. Licensed under Apache-2.0.

use prometheus::{exponential_buckets, Gauge, Histogram, HistogramVec, IntCounter, IntCounterVec};

lazy_static! {
    pub static ref SNAP_COUNTER_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_raftstore_snapshot_total",
        "Total number of raftstore snapshot processed.",
        &["type", "status"]
    )
    .unwrap();
    pub static ref CHECK_SPILT_COUNTER_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_raftstore_check_split_total",
        "Total number of raftstore split check.",
        &["type"]
    )
    .unwrap();
    pub static ref SNAP_HISTOGRAM: HistogramVec = register_histogram_vec!(
        "tikv_raftstore_snapshot_duration_seconds",
        "Bucketed histogram of raftstore snapshot process duration",
        &["type"],
        exponential_buckets(0.0005, 2.0, 20).unwrap()
    )
    .unwrap();
    pub static ref CHECK_SPILT_HISTOGRAM: Histogram = register_histogram!(
        "tikv_raftstore_check_split_duration_seconds",
        "Bucketed histogram of raftstore split check duration",
        exponential_buckets(0.0005, 2.0, 20).unwrap()
    )
    .unwrap();
    pub static ref COMPACT_RANGE_CF: HistogramVec = register_histogram_vec!(
        "tikv_compact_range_cf_duration_seconds",
        "Bucketed histogram of compact range for cf execution",
        &["cf"]
    )
    .unwrap();
    pub static ref REGION_HASH_HISTOGRAM: Histogram = register_histogram!(
        "tikv_raftstore_hash_duration_seconds",
        "Bucketed histogram of raftstore hash compution duration"
    )
    .unwrap();
    pub static ref STALE_PEER_PENDING_DELETE_RANGE_GAUGE: Gauge = register_gauge!(
        "tikv_pending_delete_ranges_of_stale_peer",
        "Total number of tikv pending delete range of stale peer"
    )
    .unwrap();
    pub static ref LOCAL_READ_REJECT: IntCounterVec = register_int_counter_vec!(
        "tikv_raftstore_local_read_reject_total",
        "Total number of rejections from the local reader.",
        &["reason"]
    )
    .unwrap();
    pub static ref LOCAL_READ_EXECUTED_REQUESTS: IntCounter = register_int_counter!(
        "tikv_raftstore_local_read_executed_requests",
        "Total number of requests directly executed by local reader."
    )
    .unwrap();
}
<commit_msg>cleanup: metrics.rs help message word correction (#5250)<commit_after>// Copyright 2016 TiKV Project Authors. Licensed under Apache-2.0.

use prometheus::{exponential_buckets, Gauge, Histogram, HistogramVec, IntCounter, IntCounterVec};

lazy_static! {
    pub static ref SNAP_COUNTER_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_raftstore_snapshot_total",
        "Total number of raftstore snapshot processed.",
        &["type", "status"]
    )
    .unwrap();
    pub static ref CHECK_SPILT_COUNTER_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_raftstore_check_split_total",
        "Total number of raftstore split check.",
        &["type"]
    )
    .unwrap();
    pub static ref SNAP_HISTOGRAM: HistogramVec = register_histogram_vec!(
        "tikv_raftstore_snapshot_duration_seconds",
        "Bucketed histogram of raftstore snapshot process duration",
        &["type"],
        exponential_buckets(0.0005, 2.0, 20).unwrap()
    )
    .unwrap();
    pub static ref CHECK_SPILT_HISTOGRAM: Histogram = register_histogram!(
        "tikv_raftstore_check_split_duration_seconds",
        "Bucketed histogram of raftstore split check duration",
        exponential_buckets(0.0005, 2.0, 20).unwrap()
    )
    .unwrap();
    pub static ref COMPACT_RANGE_CF: HistogramVec = register_histogram_vec!(
        "tikv_compact_range_cf_duration_seconds",
        "Bucketed histogram of compact range for cf execution",
        &["cf"]
    )
    .unwrap();
    pub static ref REGION_HASH_HISTOGRAM: Histogram = register_histogram!(
        "tikv_raftstore_hash_duration_seconds",
        "Bucketed histogram of raftstore hash computation duration"
    )
    .unwrap();
    pub static ref STALE_PEER_PENDING_DELETE_RANGE_GAUGE: Gauge = register_gauge!(
        "tikv_pending_delete_ranges_of_stale_peer",
        "Total number of tikv pending delete range of stale peer"
    )
    .unwrap();
    pub static ref LOCAL_READ_REJECT: IntCounterVec = register_int_counter_vec!(
        "tikv_raftstore_local_read_reject_total",
        "Total number of rejections from the local reader.",
        &["reason"]
    )
    .unwrap();
    pub static ref LOCAL_READ_EXECUTED_REQUESTS: IntCounter = register_int_counter!(
        "tikv_raftstore_local_read_executed_requests",
        "Total number of requests directly executed by local reader."
    )
    .unwrap();
}
<|endoftext|>


<commit_before>use std::io;
use std::path::{Path, PathBuf};
use std::fs::File;

use clap::{App, Arg, ArgMatches};
use hyper::method::Method;
use mime;
use multipart::client::Multipart;
use serde_json;
use walkdir::{WalkDir, Iter as WalkDirIter};
use zip;

use super::super::CliResult;
use super::super::utils::TempFile;
use super::Config;
use super::super::macho::is_macho_file;

const BATCH_SIZE : u32 = 15;

enum UploadTarget {
    Global,
    Project {
        org: String,
        project: String
    }
}

impl UploadTarget {

    pub fn get_api_path(&self) -> String {
        match *self {
            UploadTarget::Global => "/system/global-dsyms/".to_owned(),
            UploadTarget::Project { ref org, ref project } => {
                format!("/projects/{}/{}/files/dsyms/", org, project)
            }
        }
    }
}

#[derive(Debug, Deserialize)]
struct DSymFile {
    uuid: String,
    #[serde(rename="objectName")]
    object_name: String,
    #[serde(rename="cpuName")]
    cpu_name: String,
}

struct BatchIterBatch {
    pub tf: TempFile,
    pub zip: zip::ZipWriter<File>,
    pub item_count: u32,
}

struct BatchIter {
    path: PathBuf,
    wd_iter: WalkDirIter,
    batch: Option<BatchIterBatch>,
    batch_count: u32,
}

impl BatchIter {
    pub fn new<P: AsRef<Path>>(path: P) -> BatchIter {
        BatchIter {
            path: path.as_ref().to_path_buf(),
            wd_iter: WalkDir::new(&path).into_iter(),
            batch: None,
            batch_count: 0
        }
    }
}

impl Iterator for BatchIter {
    type Item = CliResult<TempFile>;

    fn next(&mut self) -> Option<CliResult<TempFile>> {
        loop {
            if let Some(dent_res) = self.wd_iter.next() {
                let dent = iter_try!(dent_res);
                let md = iter_try!(dent.metadata());
                if md.is_file() && is_macho_file(dent.path()) {
                    // if we don't have a batch yet, create a new one.  We fill
                    // up to a fixed number of items into that batch before it
                    // is being returned from the iterator.
                    let batch = match self.batch {
                        None => {
                            self.batch_count += 1;
                            println!("Creating batch #{}:", self.batch_count);
                            let tf = iter_try!(TempFile::new());
                            let zip = zip::ZipWriter::new(tf.open());
                            self.batch = Some(BatchIterBatch {
                                tf: tf,
                                zip: zip,
                                item_count: 0,
                            });
                            self.batch.as_mut().unwrap()
                        },
                        Some(ref mut val) => val,
                    };

                    let name = Path::new("DebugSymbols")
                        .join(dent.path().strip_prefix(&self.path).unwrap());
                    iter_try!(batch.zip.start_file(
                        name.to_string_lossy().into_owned(),
                        zip::CompressionMethod::Deflated));
                    println!("  {}", name.display());
                    let mut f = iter_try!(File::open(dent.path()));
                    iter_try!(io::copy(&mut f, &mut batch.zip));
                    batch.item_count += 1;
                    if batch.item_count > BATCH_SIZE {
                        break;
                    }
                }
            } else {
                break;
            }
        }
        self.batch.take().map(|val| Ok(val.tf))
    }
}

fn upload_dsyms(tf: &TempFile, config: &Config,
                target: &UploadTarget) -> CliResult<Vec<DSymFile>> {
    let req = try!(config.api_request(Method::Post, &target.get_api_path()));
    let mut mp = try!(Multipart::from_request_sized(req));
    mp.write_stream("file", &mut tf.open(), Some("archive.zip"),
        "application/zip".parse::<mime::Mime>().ok());
    let mut resp = try!(mp.send());
    Ok(try!(serde_json::from_reader(&mut resp)))
}

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b>
{
    app
        .about("uploads debug symbols to a project")
        .arg(Arg::with_name("org")
             .value_name("ORG")
             .long("org")
             .short("o")
             .help("The organization slug"))
        .arg(Arg::with_name("project")
             .value_name("PROJECT")
             .long("project")
             .short("p")
             .help("The project slug"))
        .arg(Arg::with_name("global")
             .long("global")
             .short("g")
             .help("Uploads the dsyms globally. This can only be done \
                    with super admin access for the Sentry installation"))
        .arg(Arg::with_name("path")
             .value_name("PATH")
             .help("The path to the debug symbols")
             .required(true)
             .index(1))
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> CliResult<()> {
    let path = matches.value_of("path").unwrap();
    let target = if matches.is_present("global") {
        UploadTarget::Global
    } else {
        if !matches.is_present("org") || !matches.is_present("project") {
            fail!("For non global uploads both organization and project are required");
        }
        UploadTarget::Project {
            org: matches.value_of("org").unwrap().to_owned(),
            project: matches.value_of("project").unwrap().to_owned(),
        }
    };

    println!("Uploading symbols from {}...", path);

    let iter = BatchIter::new(path);
    for tf_res in iter {
        let tf = try!(tf_res);
        println!("Uploading archive ...");
        let rv = try!(upload_dsyms(&tf, config, &target));
        if rv.len() == 0 {
            fail!("Server did not accept any debug symbols.");
        } else {
            println!("Accepted debug symbols:");
            for df in rv {
                println!("  {} ({}; {})", df.uuid, df.object_name, df.cpu_name);
            }
        }
    }

    Ok(())
}
<commit_msg>Simplified upload target code<commit_after>use std::io;
use std::path::{Path, PathBuf};
use std::fs::File;

use clap::{App, Arg, ArgMatches};
use hyper::method::Method;
use mime;
use multipart::client::Multipart;
use serde_json;
use walkdir::{WalkDir, Iter as WalkDirIter};
use zip;

use super::super::CliResult;
use super::super::utils::TempFile;
use super::Config;
use super::super::macho::is_macho_file;

const BATCH_SIZE : u32 = 15;

#[derive(Debug, Deserialize)]
struct DSymFile {
    uuid: String,
    #[serde(rename="objectName")]
    object_name: String,
    #[serde(rename="cpuName")]
    cpu_name: String,
}

struct BatchIterBatch {
    pub tf: TempFile,
    pub zip: zip::ZipWriter<File>,
    pub item_count: u32,
}

struct BatchIter {
    path: PathBuf,
    wd_iter: WalkDirIter,
    batch: Option<BatchIterBatch>,
    batch_count: u32,
}

impl BatchIter {
    pub fn new<P: AsRef<Path>>(path: P) -> BatchIter {
        BatchIter {
            path: path.as_ref().to_path_buf(),
            wd_iter: WalkDir::new(&path).into_iter(),
            batch: None,
            batch_count: 0
        }
    }
}

impl Iterator for BatchIter {
    type Item = CliResult<TempFile>;

    fn next(&mut self) -> Option<CliResult<TempFile>> {
        loop {
            if let Some(dent_res) = self.wd_iter.next() {
                let dent = iter_try!(dent_res);
                let md = iter_try!(dent.metadata());
                if md.is_file() && is_macho_file(dent.path()) {
                    // if we don't have a batch yet, create a new one.  We fill
                    // up to a fixed number of items into that batch before it
                    // is being returned from the iterator.
                    let batch = match self.batch {
                        None => {
                            self.batch_count += 1;
                            println!("Creating batch #{}:", self.batch_count);
                            let tf = iter_try!(TempFile::new());
                            let zip = zip::ZipWriter::new(tf.open());
                            self.batch = Some(BatchIterBatch {
                                tf: tf,
                                zip: zip,
                                item_count: 0,
                            });
                            self.batch.as_mut().unwrap()
                        },
                        Some(ref mut val) => val,
                    };

                    let name = Path::new("DebugSymbols")
                        .join(dent.path().strip_prefix(&self.path).unwrap());
                    iter_try!(batch.zip.start_file(
                        name.to_string_lossy().into_owned(),
                        zip::CompressionMethod::Deflated));
                    println!("  {}", name.display());
                    let mut f = iter_try!(File::open(dent.path()));
                    iter_try!(io::copy(&mut f, &mut batch.zip));
                    batch.item_count += 1;
                    if batch.item_count > BATCH_SIZE {
                        break;
                    }
                }
            } else {
                break;
            }
        }
        self.batch.take().map(|val| Ok(val.tf))
    }
}

fn upload_dsyms(tf: &TempFile, config: &Config,
                api_path: &str) -> CliResult<Vec<DSymFile>> {
    let req = try!(config.api_request(Method::Post, api_path));
    let mut mp = try!(Multipart::from_request_sized(req));
    mp.write_stream("file", &mut tf.open(), Some("archive.zip"),
        "application/zip".parse::<mime::Mime>().ok());
    let mut resp = try!(mp.send());
    Ok(try!(serde_json::from_reader(&mut resp)))
}

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b>
{
    app
        .about("uploads debug symbols to a project")
        .arg(Arg::with_name("org")
             .value_name("ORG")
             .long("org")
             .short("o")
             .help("The organization slug"))
        .arg(Arg::with_name("project")
             .value_name("PROJECT")
             .long("project")
             .short("p")
             .help("The project slug"))
        .arg(Arg::with_name("global")
             .long("global")
             .short("g")
             .help("Uploads the dsyms globally. This can only be done \
                    with super admin access for the Sentry installation"))
        .arg(Arg::with_name("path")
             .value_name("PATH")
             .help("The path to the debug symbols")
             .required(true)
             .index(1))
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> CliResult<()> {
    let path = matches.value_of("path").unwrap();
    let api_path = if matches.is_present("global") {
        "/system/global-dsyms/".to_owned()
    } else {
        if !matches.is_present("org") || !matches.is_present("project") {
            fail!("For non global uploads both organization and project are required");
        }
        format!("/projects/{}/{}/files/dsyms/",
                matches.value_of("org").unwrap(),
                matches.value_of("project").unwrap())
    };

    println!("Uploading symbols from {}...", path);

    let iter = BatchIter::new(path);
    for tf_res in iter {
        let tf = try!(tf_res);
        println!("Uploading archive ...");
        let rv = try!(upload_dsyms(&tf, config, &api_path));
        if rv.len() == 0 {
            fail!("Server did not accept any debug symbols.");
        } else {
            println!("Accepted debug symbols:");
            for df in rv {
                println!("  {} ({}; {})", df.uuid, df.object_name, df.cpu_name);
            }
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>#![macro_escape]
macro_rules! hash_module (($hash_name:ident, $hashbytes:expr, $blockbytes:expr) => (

#[link(name = "sodium")]
extern {
    fn $hash_name(h: *mut u8,
                  m: *u8,
                  mlen: c_ulonglong) -> c_int;
}

pub static HASHBYTES: uint = $hashbytes;
pub static BLOCKBYTES: uint = $blockbytes;

/**
 * Digest-structure
 */
pub struct Digest([u8, ..HASHBYTES]);

/**
 * `hash` hashes a message `m`. It returns a hash `h`.
 */
pub fn hash(m: &[u8]) -> Digest {
    unsafe {
        let mut h = [0, ..HASHBYTES];
        $hash_name(h.as_mut_ptr(), m.as_ptr(), m.len() as c_ulonglong);
        Digest(h)
    }
}

))
<commit_msg>The Digest buffer should public (fields are private by default now)<commit_after>#![macro_escape]
macro_rules! hash_module (($hash_name:ident, $hashbytes:expr, $blockbytes:expr) => (

#[link(name = "sodium")]
extern {
    fn $hash_name(h: *mut u8,
                  m: *u8,
                  mlen: c_ulonglong) -> c_int;
}

pub static HASHBYTES: uint = $hashbytes;
pub static BLOCKBYTES: uint = $blockbytes;

/**
 * Digest-structure
 */
pub struct Digest(pub [u8, ..HASHBYTES]);

/**
 * `hash` hashes a message `m`. It returns a hash `h`.
 */
pub fn hash(m: &[u8]) -> Digest {
    unsafe {
        let mut h = [0, ..HASHBYTES];
        $hash_name(h.as_mut_ptr(), m.as_ptr(), m.len() as c_ulonglong);
        Digest(h)
    }
}

))
<|endoftext|>