<commit_before>/*
 * File:   collector.cpp
 * Author: Oleg Zharkov
 *
 */

#include "collector.h"

char Collector::wazuh_host[OS_HEADER_SIZE];
int Collector::wazuh_port = 0;
char Collector::wazuh_user[OS_HEADER_SIZE];
char Collector::wazuh_pwd[OS_HEADER_SIZE];

int Collector::GetConfig() {

    //Read sinks config
    if(!sk.GetConfig()) return 0;

    if (sk.GetReportsPeriod()) status = 1;

    ConfigYaml* cy = new ConfigYaml( "collector");

    cy->addKey("wazuh_host");
    cy->addKey("wazuh_port");
    cy->addKey("wazuh_user");
    cy->addKey("wazuh_pwd");

    cy->ParsConfig();

    strncpy(wazuh_host, (char*) cy->getParameter("wazuh_host").c_str(), sizeof(wazuh_host));
    if (!strcmp (wazuh_host, "none")) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    if (!strcmp (wazuh_host, "")) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    wazuh_port = stoi(cy->getParameter("wazuh_port"));
    if (wazuh_port == 0) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    strncpy(wazuh_user, (char*) cy->getParameter("wazuh_user").c_str(), sizeof(wazuh_user));
    if (!strcmp (wazuh_user, "none")) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    if (!strcmp (wazuh_user, "")) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    strncpy(wazuh_pwd, (char*) cy->getParameter("wazuh_pwd").c_str(), sizeof(wazuh_pwd));
    if (!strcmp (wazuh_pwd, "none")) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    if (!strcmp (wazuh_pwd, "")) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    ossecServerStatus = true;

    return 1;

}

int  Collector::Open() {

    if (!sk.Open()) return 0;

    ref_id = hids->fs.filter.ref_id;

    if (ossecServerStatus) {
        string payload = GetAgentsStatus();
        if (!payload.empty()){
            SysLog("connection between Wazuh server and Altprobe is established");
            ParsAgentsStatus(payload);
        }
        else ossecServerStatus = false;
    }

    return 1;
}

void  Collector::Close() {

    sk.Close();

}

int Collector::Go(void) {

    struct timeval start, end;
    long seconds = 0;

    while(1) {
        gettimeofday(&start, NULL);
        while (sk.GetReportsPeriod() > seconds) {
            gettimeofday(&end, NULL);
            seconds  = end.tv_sec  - start.tv_sec;

            usleep(GetGosleepTimer()*60);
        }
        RoutineJob();
        seconds = 0;
    }

    return 1;
}

void Collector::RoutineJob() {

    stringstream ss;

    unsigned long chids = hids->ResetEventsCounter();
    unsigned long cnids = nids->ResetEventsCounter();
    unsigned long cmetrics = met->ResetEventsCounter();
    unsigned long cstatflows = stat_flows->ResetEventsCounter();
    unsigned long cremlog = rem_log->ResetEventsCounter();
    unsigned long vremlog = rem_log->ResetEventsVolume();
    unsigned long cremstat = rem_stat->ResetEventsCounter();
    unsigned long vremstat = rem_stat->ResetEventsVolume();

    ss << "{ \"type\": \"node_monitor\", \"data\": { \"ref_id\": \"";
    ss << ref_id;

    ss << "\", \"hids\": ";
    ss << to_string(chids);

    ss << ", \"nids\": ";
    ss << to_string(cnids);

    ss << ", \"metrics\": ";
    ss << to_string(cmetrics);

    ss << ", \"flows\": ";
    ss << to_string(cstatflows);

    ss << ", \"log_counter\": ";
    ss << to_string(cremlog);

    ss << ", \"log_volume\": ";
    ss << to_string(vremlog);

    ss << ", \"stat_counter\": ";
    ss << to_string(cremstat);

    ss << ", \"stat_volume\": ";
    ss << to_string(vremstat);

    ss << ", \"time_of_survey\": \"";
    ss << GetNodeTime();
    ss << "\" } }";

    q_stats_collr.push(ss.str());

    ss.str("");
    ss.clear();

    unsigned long mapp = stat_flows->mem_mon.applications;
    unsigned long mcount = stat_flows->mem_mon.countries;
    unsigned long mdns = stat_flows->mem_mon.dns_queries;
    unsigned long mssh = stat_flows->mem_mon.ssh_sessions;
    unsigned long mtopt = stat_flows->mem_mon.top_talkers;
    unsigned long mahids = stat_ids->mem_mon.hids_alerts_list;
    unsigned long manids = stat_ids->mem_mon.nids_alerts_list;
    unsigned long mfimc = stat_ids->mem_mon.fim_cause;
    unsigned long mfimf = stat_ids->mem_mon.fim_file;
    unsigned long mhidsh = stat_ids->mem_mon.hids_hostname;
    unsigned long mhidsl = stat_ids->mem_mon.hids_location;
    unsigned long midsc = stat_ids->mem_mon.ids_category;
    unsigned long midse = stat_ids->mem_mon.ids_event;
    unsigned long mnidsd = stat_ids->mem_mon.nids_dstip;
    unsigned long mnidss = stat_ids->mem_mon.nids_srcip;

    ss << "{ \"type\": \"node_memory\", \"data\": { \"ref_id\": \"";
    ss << ref_id;

    ss << "\", \"flows_application\": ";
    ss << to_string(mapp);

    ss << ", \"flows_countries\": ";
    ss << to_string(mcount);

    ss << ", \"flows_dns\": ";
    ss << to_string(mdns);

    ss << ", \"flows_ssh\": ";
    ss << to_string(mssh);

    ss << ", \"flows_talkers\": ";
    ss << to_string(mtopt);

    ss << ", \"hids_alerts\": ";
    ss << to_string(mahids);

    ss << ", \"nids_alerts\": ";
    ss << to_string(manids);

    ss << ", \"fim_cause\": ";
    ss << to_string(mfimc);

    ss << ", \"fim_file\": ";
    ss << to_string(mfimf);

    ss << ", \"hids_hostname\": ";
    ss << to_string(mhidsh);

    ss << ", \"hids_location\": ";
    ss << to_string(mhidsl);

    ss << ", \"ids_category\": ";
    ss << to_string(midse);

    ss << ", \"ids_event\": ";
    ss << to_string(midse);

    ss << ", \"nids_dstip\": ";
    ss << to_string(mnidsd);

    ss << ", \"nids_srcip\": ";
    ss << to_string(mnidss);

    ss << ", \"time_of_survey\": \"";
    ss << GetNodeTime();
    ss << "\" } }";

    q_stats_collr.push(ss.str());

    ss.str("");
    ss.clear();

    unsigned long magent = fs.agents_list.size();
    unsigned long mhnetf = fs.filter.home_nets.size();
    unsigned long mhidsf = fs.filter.hids.bwl.size();
    unsigned long mnidsf = fs.filter.nids.bwl.size();
    unsigned long mmetf = 0;
    unsigned long mtraf = fs.filter.traf.th.size();

    ss << "{ \"type\": \"node_filters\", \"data\": { \"ref_id\": \"";
    ss << ref_id;

    ss << "\", \"agent_list\": ";
    ss << to_string(magent);

    ss << ", \"hnet_list\": ";
    ss << to_string(mhnetf);

    ss << ", \"hids_filters\": ";
    ss << to_string(mhidsf);

    ss << ", \"nids_filters\": ";
    ss << to_string(mnidsf);

    ss << ", \"metric_filters\": ";
    ss << to_string(mmetf);

    ss << ", \"traffic_filters\": ";
    ss << to_string(mtraf);

    ss << ", \"time_of_survey\": \"";
    ss << GetNodeTime();
    ss << "\" } }";

    q_stats_collr.push(ss.str());

    ss.str("");
    ss.clear();

    if (ossecServerStatus) {
        string payload = GetAgentsStatus();
        if (!payload.empty()) {

            ParsAgentsStatus(payload);

            if (fs.agents_list.size() != 0) {

                std::vector<Agent>::iterator i, end;
                int j = 0;

                string report = "{ \"type\": \"agents_list\", \"data\" : [ ";

                for (i = fs.agents_list.begin(), end = fs.agents_list.end(); i != end; ++i) {

                    report += "{ \"id\": \"";
                    report += i->id;

                    report += "\", \"ip\": \"";
                    report += i->ip;

                    report += "\", \"name\": \"";
                    report += i->name;

                    report += "\", \"status\": \"";
                    report += i->status;

                    report += "\", \"date_add\": \"";
                    report += i->dateAdd;

                    report += "\", \"version\": \"";
                    report += i->version;

                    report += "\", \"manager_host\": \"";
                    report += i->manager_host;

                    report += "\", \"os_platform\": \"";
                    report += i->os_platform;

                    report += "\", \"os_version\": \"";
                    report += i->os_version;

                    report += "\", \"os_name\": \"";
                    report += i->os_name;

                    report += "\", \"time_of_survey\": \"";
                    report +=  GetNodeTime();

                    report += "\" }";

                    if ( j < fs.agents_list.size() - 1) {
                        report += ", ";
                        j++;
                    }
                }

                report += " ] }";
                q_stats_collr.push(report);
            }
        }
    }
}

string Collector::GetAgentsStatus() {
    try
    {
        boost::asio::io_service io_service;

        string hostAddress;
        string ip(wazuh_host);
        stringstream ss;
        ss << wazuh_port;
        string port = ss.str();

        if (wazuh_port != 80) {
            hostAddress = ip + ":" + port;
        } else {

            hostAddress = ip;
        }

        string user(wazuh_user);
        string pwd(wazuh_pwd);
        string token = user + ":" + pwd;

        string encoded;

        if (!Base64::Encode(token, &encoded)) {
            return "";
        }

        string queryStr = "/agents?pretty";

        tcp::resolver resolver(io_service);
        tcp::resolver::query query(ip, port);
        tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

        tcp::socket socket(io_service);
        boost::asio::connect(socket, endpoint_iterator);

        boost::asio::streambuf request;
        ostream request_stream(&request);
        request_stream << "GET " << queryStr << " HTTP/1.1\r\n";
        request_stream << "Host: " << hostAddress << "\r\n";
        request_stream << "Authorization: Basic "<< encoded << "\r\n";
        request_stream << "Accept: */*\r\n";
        request_stream << "Connection: close\r\n\r\n";

        boost::asio::write(socket, request);

        boost::asio::streambuf response;
        boost::asio::read_until(socket, response, "\r\n");

        istream response_stream(&response);
        string http_version;
        response_stream >> http_version;
        unsigned int status_code;
        response_stream >> status_code;
        string status_message;
        getline(response_stream, status_message);

        if (!response_stream || http_version.substr(0, 5) != "HTTP/") return NULL;

        if (status_code != 200) return "";

        boost::asio::read_until(socket, response, "\r\n\r\n");

        string header;
        while (getline(response_stream, header) && header != "\r") { }

        stringstream  payload;
        if (response.size() > 0) {
            payload << &response;
        }

        boost::system::error_code error;
        while (boost::asio::read(socket, response,boost::asio::transfer_at_least(1), error)) {
            payload << &response;
        }

        if (error != boost::asio::error::eof) {
            throw boost::system::system_error(error);
        }

        return payload.str();
    }
    catch (std::exception& e) {
        return "";
    }

    return "";

}

void Collector::ParsAgentsStatus (string status) {

    stringstream ss(status);

    try {

        bpt::ptree pt;
        bpt::read_json(ss, pt);

        int error =  pt.get<int>("error");

        int totalItems =  pt.get<int>("data.totalItems");

        bpt::ptree agents_ptree = pt.get_child("data.items");

        BOOST_FOREACH(bpt::ptree::value_type &agents, agents_ptree) {

            string id = agents.second.get<string>("id");
            string ip = agents.second.get<string>("ip");
            string name = agents.second.get<string>("name");
            string status = agents.second.get<string>("status");
            string dateAdd = agents.second.get<string>("dateAdd");
            string version = agents.second.get<string>("version");
            string manager_host = agents.second.get<string>("manager_host");
            string os_platform = agents.second.get<string>("os.platform", "indef");
            string os_version = agents.second.get<string>("os.version", "indef");
            string os_name = agents.second.get<string>("os.name", "indef");

            fs.UpdateAgentsList(id, ip, name, status, dateAdd, version, manager_host, os_platform, os_version, os_name);
        }

        pt.clear();

    } catch (const std::exception & ex) {
        SysLog((char*) ex.what());
    }

    return;
}

<commit_msg>inform about connection error<commit_after>/*
 * File:   collector.cpp
 * Author: Oleg Zharkov
 *
 */

#include "collector.h"

char Collector::wazuh_host[OS_HEADER_SIZE];
int Collector::wazuh_port = 0;
char Collector::wazuh_user[OS_HEADER_SIZE];
char Collector::wazuh_pwd[OS_HEADER_SIZE];

int Collector::GetConfig() {

    //Read sinks config
    if(!sk.GetConfig()) return 0;

    if (sk.GetReportsPeriod()) status = 1;

    ConfigYaml* cy = new ConfigYaml( "collector");

    cy->addKey("wazuh_host");
    cy->addKey("wazuh_port");
    cy->addKey("wazuh_user");
    cy->addKey("wazuh_pwd");

    cy->ParsConfig();

    strncpy(wazuh_host, (char*) cy->getParameter("wazuh_host").c_str(), sizeof(wazuh_host));
    if (!strcmp (wazuh_host, "none")) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    if (!strcmp (wazuh_host, "")) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    wazuh_port = stoi(cy->getParameter("wazuh_port"));
    if (wazuh_port == 0) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    strncpy(wazuh_user, (char*) cy->getParameter("wazuh_user").c_str(), sizeof(wazuh_user));
    if (!strcmp (wazuh_user, "none")) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    if (!strcmp (wazuh_user, "")) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    strncpy(wazuh_pwd, (char*) cy->getParameter("wazuh_pwd").c_str(), sizeof(wazuh_pwd));
    if (!strcmp (wazuh_pwd, "none")) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    if (!strcmp (wazuh_pwd, "")) {
        ossecServerStatus =false;
        SysLog("config file notification: interface to Wazuh server is disabled");
        return 1;
    }

    ossecServerStatus = true;

    return 1;

}

int  Collector::Open() {

    if (!sk.Open()) return 0;

    ref_id = hids->fs.filter.ref_id;

    if (ossecServerStatus) {
        string payload = GetAgentsStatus();
        if (!payload.empty()){
            SysLog("connection between Wazuh server and Altprobe is established");
            ParsAgentsStatus(payload);
        }
        else {
            ossecServerStatus = false;
            SysLog("error of connection between Wazuh server and Altprobe");
        }
    }

    return 1;
}

void  Collector::Close() {

    sk.Close();

}

int Collector::Go(void) {

    struct timeval start, end;
    long seconds = 0;

    while(1) {
        gettimeofday(&start, NULL);
        while (sk.GetReportsPeriod() > seconds) {
            gettimeofday(&end, NULL);
            seconds  = end.tv_sec  - start.tv_sec;

            usleep(GetGosleepTimer()*60);
        }
        RoutineJob();
        seconds = 0;
    }

    return 1;
}

void Collector::RoutineJob() {

    stringstream ss;

    unsigned long chids = hids->ResetEventsCounter();
    unsigned long cnids = nids->ResetEventsCounter();
    unsigned long cmetrics = met->ResetEventsCounter();
    unsigned long cstatflows = stat_flows->ResetEventsCounter();
    unsigned long cremlog = rem_log->ResetEventsCounter();
    unsigned long vremlog = rem_log->ResetEventsVolume();
    unsigned long cremstat = rem_stat->ResetEventsCounter();
    unsigned long vremstat = rem_stat->ResetEventsVolume();

    ss << "{ \"type\": \"node_monitor\", \"data\": { \"ref_id\": \"";
    ss << ref_id;

    ss << "\", \"hids\": ";
    ss << to_string(chids);

    ss << ", \"nids\": ";
    ss << to_string(cnids);

    ss << ", \"metrics\": ";
    ss << to_string(cmetrics);

    ss << ", \"flows\": ";
    ss << to_string(cstatflows);

    ss << ", \"log_counter\": ";
    ss << to_string(cremlog);

    ss << ", \"log_volume\": ";
    ss << to_string(vremlog);

    ss << ", \"stat_counter\": ";
    ss << to_string(cremstat);

    ss << ", \"stat_volume\": ";
    ss << to_string(vremstat);

    ss << ", \"time_of_survey\": \"";
    ss << GetNodeTime();
    ss << "\" } }";

    q_stats_collr.push(ss.str());

    ss.str("");
    ss.clear();

    unsigned long mapp = stat_flows->mem_mon.applications;
    unsigned long mcount = stat_flows->mem_mon.countries;
    unsigned long mdns = stat_flows->mem_mon.dns_queries;
    unsigned long mssh = stat_flows->mem_mon.ssh_sessions;
    unsigned long mtopt = stat_flows->mem_mon.top_talkers;
    unsigned long mahids = stat_ids->mem_mon.hids_alerts_list;
    unsigned long manids = stat_ids->mem_mon.nids_alerts_list;
    unsigned long mfimc = stat_ids->mem_mon.fim_cause;
    unsigned long mfimf = stat_ids->mem_mon.fim_file;
    unsigned long mhidsh = stat_ids->mem_mon.hids_hostname;
    unsigned long mhidsl = stat_ids->mem_mon.hids_location;
    unsigned long midsc = stat_ids->mem_mon.ids_category;
    unsigned long midse = stat_ids->mem_mon.ids_event;
    unsigned long mnidsd = stat_ids->mem_mon.nids_dstip;
    unsigned long mnidss = stat_ids->mem_mon.nids_srcip;

    ss << "{ \"type\": \"node_memory\", \"data\": { \"ref_id\": \"";
    ss << ref_id;

    ss << "\", \"flows_application\": ";
    ss << to_string(mapp);

    ss << ", \"flows_countries\": ";
    ss << to_string(mcount);

    ss << ", \"flows_dns\": ";
    ss << to_string(mdns);

    ss << ", \"flows_ssh\": ";
    ss << to_string(mssh);

    ss << ", \"flows_talkers\": ";
    ss << to_string(mtopt);

    ss << ", \"hids_alerts\": ";
    ss << to_string(mahids);

    ss << ", \"nids_alerts\": ";
    ss << to_string(manids);

    ss << ", \"fim_cause\": ";
    ss << to_string(mfimc);

    ss << ", \"fim_file\": ";
    ss << to_string(mfimf);

    ss << ", \"hids_hostname\": ";
    ss << to_string(mhidsh);

    ss << ", \"hids_location\": ";
    ss << to_string(mhidsl);

    ss << ", \"ids_category\": ";
    ss << to_string(midse);

    ss << ", \"ids_event\": ";
    ss << to_string(midse);

    ss << ", \"nids_dstip\": ";
    ss << to_string(mnidsd);

    ss << ", \"nids_srcip\": ";
    ss << to_string(mnidss);

    ss << ", \"time_of_survey\": \"";
    ss << GetNodeTime();
    ss << "\" } }";

    q_stats_collr.push(ss.str());

    ss.str("");
    ss.clear();

    unsigned long magent = fs.agents_list.size();
    unsigned long mhnetf = fs.filter.home_nets.size();
    unsigned long mhidsf = fs.filter.hids.bwl.size();
    unsigned long mnidsf = fs.filter.nids.bwl.size();
    unsigned long mmetf = 0;
    unsigned long mtraf = fs.filter.traf.th.size();

    ss << "{ \"type\": \"node_filters\", \"data\": { \"ref_id\": \"";
    ss << ref_id;

    ss << "\", \"agent_list\": ";
    ss << to_string(magent);

    ss << ", \"hnet_list\": ";
    ss << to_string(mhnetf);

    ss << ", \"hids_filters\": ";
    ss << to_string(mhidsf);

    ss << ", \"nids_filters\": ";
    ss << to_string(mnidsf);

    ss << ", \"metric_filters\": ";
    ss << to_string(mmetf);

    ss << ", \"traffic_filters\": ";
    ss << to_string(mtraf);

    ss << ", \"time_of_survey\": \"";
    ss << GetNodeTime();
    ss << "\" } }";

    q_stats_collr.push(ss.str());

    ss.str("");
    ss.clear();

    if (ossecServerStatus) {
        string payload = GetAgentsStatus();
        if (!payload.empty()) {

            ParsAgentsStatus(payload);

            if (fs.agents_list.size() != 0) {

                std::vector<Agent>::iterator i, end;
                int j = 0;

                string report = "{ \"type\": \"agents_list\", \"data\" : [ ";

                for (i = fs.agents_list.begin(), end = fs.agents_list.end(); i != end; ++i) {

                    report += "{ \"id\": \"";
                    report += i->id;

                    report += "\", \"ip\": \"";
                    report += i->ip;

                    report += "\", \"name\": \"";
                    report += i->name;

                    report += "\", \"status\": \"";
                    report += i->status;

                    report += "\", \"date_add\": \"";
                    report += i->dateAdd;

                    report += "\", \"version\": \"";
                    report += i->version;

                    report += "\", \"manager_host\": \"";
                    report += i->manager_host;

                    report += "\", \"os_platform\": \"";
                    report += i->os_platform;

                    report += "\", \"os_version\": \"";
                    report += i->os_version;

                    report += "\", \"os_name\": \"";
                    report += i->os_name;

                    report += "\", \"time_of_survey\": \"";
                    report +=  GetNodeTime();

                    report += "\" }";

                    if ( j < fs.agents_list.size() - 1) {
                        report += ", ";
                        j++;
                    }
                }

                report += " ] }";
                q_stats_collr.push(report);
            }
        }
    }
}

string Collector::GetAgentsStatus() {
    try
    {
        boost::asio::io_service io_service;

        string hostAddress;
        string ip(wazuh_host);
        stringstream ss;
        ss << wazuh_port;
        string port = ss.str();

        if (wazuh_port != 80) {
            hostAddress = ip + ":" + port;
        } else {

            hostAddress = ip;
        }

        string user(wazuh_user);
        string pwd(wazuh_pwd);
        string token = user + ":" + pwd;

        string encoded;

        if (!Base64::Encode(token, &encoded)) {
            return "";
        }

        string queryStr = "/agents?pretty";

        tcp::resolver resolver(io_service);
        tcp::resolver::query query(ip, port);
        tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

        tcp::socket socket(io_service);
        boost::asio::connect(socket, endpoint_iterator);

        boost::asio::streambuf request;
        ostream request_stream(&request);
        request_stream << "GET " << queryStr << " HTTP/1.1\r\n";
        request_stream << "Host: " << hostAddress << "\r\n";
        request_stream << "Authorization: Basic "<< encoded << "\r\n";
        request_stream << "Accept: */*\r\n";
        request_stream << "Connection: close\r\n\r\n";

        boost::asio::write(socket, request);

        boost::asio::streambuf response;
        boost::asio::read_until(socket, response, "\r\n");

        istream response_stream(&response);
        string http_version;
        response_stream >> http_version;
        unsigned int status_code;
        response_stream >> status_code;
        string status_message;
        getline(response_stream, status_message);

        if (!response_stream || http_version.substr(0, 5) != "HTTP/") return NULL;

        if (status_code != 200) return "";

        boost::asio::read_until(socket, response, "\r\n\r\n");

        string header;
        while (getline(response_stream, header) && header != "\r") { }

        stringstream  payload;
        if (response.size() > 0) {
            payload << &response;
        }

        boost::system::error_code error;
        while (boost::asio::read(socket, response,boost::asio::transfer_at_least(1), error)) {
            payload << &response;
        }

        if (error != boost::asio::error::eof) {
            throw boost::system::system_error(error);
        }

        return payload.str();
    }
    catch (std::exception& e) {
        return "";
    }

    return "";

}

void Collector::ParsAgentsStatus (string status) {

    stringstream ss(status);

    try {

        bpt::ptree pt;
        bpt::read_json(ss, pt);

        int error =  pt.get<int>("error");

        int totalItems =  pt.get<int>("data.totalItems");

        bpt::ptree agents_ptree = pt.get_child("data.items");

        BOOST_FOREACH(bpt::ptree::value_type &agents, agents_ptree) {

            string id = agents.second.get<string>("id");
            string ip = agents.second.get<string>("ip");
            string name = agents.second.get<string>("name");
            string status = agents.second.get<string>("status");
            string dateAdd = agents.second.get<string>("dateAdd");
            string version = agents.second.get<string>("version");
            string manager_host = agents.second.get<string>("manager_host");
            string os_platform = agents.second.get<string>("os.platform", "indef");
            string os_version = agents.second.get<string>("os.version", "indef");
            string os_name = agents.second.get<string>("os.name", "indef");

            fs.UpdateAgentsList(id, ip, name, status, dateAdd, version, manager_host, os_platform, os_version, os_name);
        }

        pt.clear();

    } catch (const std::exception & ex) {
        SysLog((char*) ex.what());
    }

    return;
}

<|endoftext|>


<commit_before>#ifndef completion_hh_INCLUDED
#define completion_hh_INCLUDED

#include <functional>
#include <algorithm>

#include "units.hh"
#include "string.hh"
#include "vector.hh"
#include "ranked_match.hh"

namespace Kakoune
{

class Context;

using CandidateList = Vector<String>;

struct Completions
{
    CandidateList candidates;
    ByteCount start;
    ByteCount end;

    Completions()
        : start(0), end(0) {}

    Completions(ByteCount start, ByteCount end)
        : start(start), end(end) {}

    Completions(ByteCount start, ByteCount end, CandidateList candidates)
        : start(start), end(end), candidates(std::move(candidates)) {}
};

enum class CompletionFlags
{
    None,
    Fast
};
using Completer = std::function<Completions (const Context&, CompletionFlags,
                                             StringView, ByteCount)>;

inline Completions complete_nothing(const Context& context, CompletionFlags,
                                    StringView, ByteCount cursor_pos)
{
    return Completions(cursor_pos, cursor_pos);
}

Completions shell_complete(const Context& context, CompletionFlags,
                           StringView, ByteCount cursor_pos);

inline Completions offset_pos(Completions completion, ByteCount offset)
{
    return { completion.start + offset, completion.end + offset,
             std::move(completion.candidates) };
}

template<typename Container>
CandidateList complete(StringView query, ByteCount cursor_pos,
                       const Container& container)
{
    using std::begin;
    static_assert(not std::is_same<decltype(*begin(container)), String>::value,
                  "complete require long lived strings, not temporaries");

    query = query.substr(0, cursor_pos);
    Vector<RankedMatch> matches;
    for (const auto& str : container)
    {
        if (RankedMatch match{str, query})
            matches.push_back(match);
    }
    std::sort(matches.begin(), matches.end());
    CandidateList res;
    for (auto& m : matches)
        res.push_back(m.candidate().str());
    return res;
}

}
#endif // completion_hh_INCLUDED
<commit_msg>Small code tweak<commit_after>#ifndef completion_hh_INCLUDED
#define completion_hh_INCLUDED

#include <functional>
#include <algorithm>

#include "units.hh"
#include "string.hh"
#include "vector.hh"
#include "ranked_match.hh"

namespace Kakoune
{

class Context;

using CandidateList = Vector<String>;

struct Completions
{
    CandidateList candidates;
    ByteCount start;
    ByteCount end;

    Completions()
        : start(0), end(0) {}

    Completions(ByteCount start, ByteCount end)
        : start(start), end(end) {}

    Completions(ByteCount start, ByteCount end, CandidateList candidates)
        : start(start), end(end), candidates(std::move(candidates)) {}
};

enum class CompletionFlags
{
    None,
    Fast
};
using Completer = std::function<Completions (const Context&, CompletionFlags,
                                             StringView, ByteCount)>;

inline Completions complete_nothing(const Context& context, CompletionFlags,
                                    StringView, ByteCount cursor_pos)
{
    return {cursor_pos, cursor_pos};
}

Completions shell_complete(const Context& context, CompletionFlags,
                           StringView, ByteCount cursor_pos);

inline Completions offset_pos(Completions completion, ByteCount offset)
{
    return { completion.start + offset, completion.end + offset,
             std::move(completion.candidates) };
}

template<typename Container>
CandidateList complete(StringView query, ByteCount cursor_pos,
                       const Container& container)
{
    using std::begin;
    static_assert(not std::is_same<decltype(*begin(container)), String>::value,
                  "complete require long lived strings, not temporaries");

    query = query.substr(0, cursor_pos);
    Vector<RankedMatch> matches;
    for (const auto& str : container)
    {
        if (RankedMatch match{str, query})
            matches.push_back(match);
    }
    std::sort(matches.begin(), matches.end());
    CandidateList res;
    for (auto& m : matches)
        res.push_back(m.candidate().str());
    return res;
}

}
#endif // completion_hh_INCLUDED
<|endoftext|>


<commit_before>#include "node.hpp"
#include "helpers.hpp"

#include "core/Log.h"
#include "core/opengl.hpp"

#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

void
Node::render(glm::mat4 const& view_projection, glm::mat4 const& parent_transform) const
{
	if (_program == nullptr) {
		LogError("Node \"%s\" can not be rendered due to lacking a shader program.", _name.c_str() + 7);
		return;
	}

	render(view_projection, parent_transform * _transform.GetMatrix(), *_program, _set_uniforms);
}

void
Node::render(glm::mat4 const& view_projection, glm::mat4 const& world, GLuint program, std::function<void (GLuint)> const& set_uniforms) const
{
	if (program == 0u) {
		LogError("Node \"%s\" can not be rendered with the specified shader program (currently set to 0).", _name.c_str() + 7);
		return;
	}
	if (_vao == 0u) {
		LogError("Node \"%s\" can not be rendered due to lacking a VAO (currently set to 0).", _name.c_str() + 7);
		return;
	}

	utils::opengl::debug::beginDebugGroup(_name);

	glUseProgram(program);

	auto const normal_model_to_world = glm::transpose(glm::inverse(world));

	set_uniforms(program);

	glUniformMatrix4fv(glGetUniformLocation(program, "vertex_model_to_world"), 1, GL_FALSE, glm::value_ptr(world));
	glUniformMatrix4fv(glGetUniformLocation(program, "normal_model_to_world"), 1, GL_FALSE, glm::value_ptr(normal_model_to_world));
	glUniformMatrix4fv(glGetUniformLocation(program, "vertex_world_to_clip"), 1, GL_FALSE, glm::value_ptr(view_projection));

	for (size_t i = 0u; i < _textures.size(); ++i) {
		auto const& texture = _textures[i];
		glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(i));
		glBindTexture(std::get<2>(texture), std::get<1>(texture));
		glUniform1i(glGetUniformLocation(program, std::get<0>(texture).c_str()), static_cast<GLint>(i));

		std::string texture_presence_var_name = "has_" + std::get<0>(texture);
		glUniform1i(glGetUniformLocation(program, texture_presence_var_name.c_str()), 1);
	}

	glUniform3fv(glGetUniformLocation(program, "diffuse_colour"), 1, glm::value_ptr(_constants.diffuse));
	glUniform3fv(glGetUniformLocation(program, "specular_colour"), 1, glm::value_ptr(_constants.specular));
	glUniform3fv(glGetUniformLocation(program, "ambient_colour"), 1, glm::value_ptr(_constants.ambient));
	glUniform3fv(glGetUniformLocation(program, "emissive_colour"), 1, glm::value_ptr(_constants.emissive));
	glUniform1f(glGetUniformLocation(program, "shininess_value"), _constants.shininess);
	glUniform1f(glGetUniformLocation(program, "index_of_refraction_value"), _constants.indexOfRefraction);
	glUniform1f(glGetUniformLocation(program, "opacity_value"), _constants.opacity);

	glBindVertexArray(_vao);
	if (_has_indices)
		glDrawElements(_drawing_mode, _indices_nb, GL_UNSIGNED_INT, reinterpret_cast<GLvoid const*>(0x0));
	else
		glDrawArrays(_drawing_mode, 0, _vertices_nb);
	glBindVertexArray(0u);

	for (auto const& texture : _textures) {
		glBindTexture(std::get<2>(texture), 0);
		glUniform1i(glGetUniformLocation(program, std::get<0>(texture).c_str()), 0);

		std::string texture_presence_var_name = "has_" + std::get<0>(texture);
		glUniform1i(glGetUniformLocation(program, texture_presence_var_name.c_str()), 0);
	}

	glUseProgram(0u);

	utils::opengl::debug::endDebugGroup();
}

void
Node::set_geometry(bonobo::mesh_data const& shape)
{
	if (shape.vao == 0u) {
		LogError("The shape's VAO can not be 0; this operation will be discarded.");
		return;
	}

	_vao = shape.vao;
	_vertices_nb = static_cast<GLsizei>(shape.vertices_nb);
	_indices_nb = static_cast<GLsizei>(shape.indices_nb);
	_drawing_mode = shape.drawing_mode;
	_has_indices = shape.ibo != 0u;
	_name = std::string("Render ") + shape.name;

	if (!shape.bindings.empty()) {
		for (auto const& binding : shape.bindings)
			add_texture(binding.first, binding.second, GL_TEXTURE_2D);
	}

	_constants = shape.material;
}

void
Node::set_material_constants(bonobo::material_data const& constants)
{
	_constants = constants;
}

void
Node::set_program(GLuint const* const program, std::function<void (GLuint)> const& set_uniforms)
{
	if (program == nullptr) {
		LogError("Program can not be a null pointer; this operation will be discarded.");
		return;
	}

	_program = program;
	_set_uniforms = set_uniforms;
}

void
Node::set_name(std::string const& name)
{
	_name = std::string("Render ") + name;
}

size_t
Node::get_indices_nb() const
{
	return static_cast<size_t>(_indices_nb);
}

void
Node::set_indices_nb(size_t const& indices_nb)
{
	_indices_nb = static_cast<GLsizei>(indices_nb);
}

void
Node::add_texture(std::string const& name, GLuint tex_id, GLenum type)
{
	GLint max_combined_texture_image_units{-1};
	glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);
	std::size_t const max_active_texture_count
		= (max_combined_texture_image_units > 0) ? static_cast<std::size_t>(max_combined_texture_image_units)
		                                         : 80; // OpenGL 4.x guarantees at least 80.

	if (_textures.size() >= max_active_texture_count) {
		LogWarning("Trying to add more textures to an object than supported (%llu); the texture %s with ID %u will **not** be added. If you really need that many textures, do not use the `Node` class and roll your own solution instead.",
		           max_active_texture_count, name.c_str(), tex_id);
		return;
	}
	if (tex_id == 0u) {
		LogWarning("0 is not a valid texture ID; the texture %s (with ID %u) will **not** be added.",
		           name.c_str(), tex_id);
		return;
	}

	_textures.emplace_back(name, tex_id, type);
}

void
Node::add_child(Node const* child)
{
	if (child == nullptr) {
		LogWarning("Trying to add a null pointer as child: this will be discarded.");
		return;
	}

	_children.emplace_back(child);
}

size_t
Node::get_children_nb() const
{
	return _children.size();
}

Node const*
Node::get_child(size_t index) const
{
	assert(index < _children.size());
	return _children[index];
}

TRSTransformf const&
Node::get_transform() const
{
	return _transform;
}

TRSTransformf&
Node::get_transform()
{
	return _transform;
}
<commit_msg>Revert "core: Error out with message if lacking VAO or program"<commit_after>#include "node.hpp"
#include "helpers.hpp"

#include "core/Log.h"
#include "core/opengl.hpp"

#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

void
Node::render(glm::mat4 const& view_projection, glm::mat4 const& parent_transform) const
{
	if (_program != nullptr)
		render(view_projection, parent_transform * _transform.GetMatrix(), *_program, _set_uniforms);
}

void
Node::render(glm::mat4 const& view_projection, glm::mat4 const& world, GLuint program, std::function<void (GLuint)> const& set_uniforms) const
{
	if (_vao == 0u || program == 0u)
		return;

	utils::opengl::debug::beginDebugGroup(_name);

	glUseProgram(program);

	auto const normal_model_to_world = glm::transpose(glm::inverse(world));

	set_uniforms(program);

	glUniformMatrix4fv(glGetUniformLocation(program, "vertex_model_to_world"), 1, GL_FALSE, glm::value_ptr(world));
	glUniformMatrix4fv(glGetUniformLocation(program, "normal_model_to_world"), 1, GL_FALSE, glm::value_ptr(normal_model_to_world));
	glUniformMatrix4fv(glGetUniformLocation(program, "vertex_world_to_clip"), 1, GL_FALSE, glm::value_ptr(view_projection));

	for (size_t i = 0u; i < _textures.size(); ++i) {
		auto const& texture = _textures[i];
		glActiveTexture(GL_TEXTURE0 + static_cast<GLenum>(i));
		glBindTexture(std::get<2>(texture), std::get<1>(texture));
		glUniform1i(glGetUniformLocation(program, std::get<0>(texture).c_str()), static_cast<GLint>(i));

		std::string texture_presence_var_name = "has_" + std::get<0>(texture);
		glUniform1i(glGetUniformLocation(program, texture_presence_var_name.c_str()), 1);
	}

	glUniform3fv(glGetUniformLocation(program, "diffuse_colour"), 1, glm::value_ptr(_constants.diffuse));
	glUniform3fv(glGetUniformLocation(program, "specular_colour"), 1, glm::value_ptr(_constants.specular));
	glUniform3fv(glGetUniformLocation(program, "ambient_colour"), 1, glm::value_ptr(_constants.ambient));
	glUniform3fv(glGetUniformLocation(program, "emissive_colour"), 1, glm::value_ptr(_constants.emissive));
	glUniform1f(glGetUniformLocation(program, "shininess_value"), _constants.shininess);
	glUniform1f(glGetUniformLocation(program, "index_of_refraction_value"), _constants.indexOfRefraction);
	glUniform1f(glGetUniformLocation(program, "opacity_value"), _constants.opacity);

	glBindVertexArray(_vao);
	if (_has_indices)
		glDrawElements(_drawing_mode, _indices_nb, GL_UNSIGNED_INT, reinterpret_cast<GLvoid const*>(0x0));
	else
		glDrawArrays(_drawing_mode, 0, _vertices_nb);
	glBindVertexArray(0u);

	for (auto const& texture : _textures) {
		glBindTexture(std::get<2>(texture), 0);
		glUniform1i(glGetUniformLocation(program, std::get<0>(texture).c_str()), 0);

		std::string texture_presence_var_name = "has_" + std::get<0>(texture);
		glUniform1i(glGetUniformLocation(program, texture_presence_var_name.c_str()), 0);
	}

	glUseProgram(0u);

	utils::opengl::debug::endDebugGroup();
}

void
Node::set_geometry(bonobo::mesh_data const& shape)
{
	_vao = shape.vao;
	_vertices_nb = static_cast<GLsizei>(shape.vertices_nb);
	_indices_nb = static_cast<GLsizei>(shape.indices_nb);
	_drawing_mode = shape.drawing_mode;
	_has_indices = shape.ibo != 0u;
	_name = std::string("Render ") + shape.name;

	if (!shape.bindings.empty()) {
		for (auto const& binding : shape.bindings)
			add_texture(binding.first, binding.second, GL_TEXTURE_2D);
	}

	_constants = shape.material;
}

void
Node::set_material_constants(bonobo::material_data const& constants)
{
	_constants = constants;
}

void
Node::set_program(GLuint const* const program, std::function<void (GLuint)> const& set_uniforms)
{
	if (program == nullptr) {
		LogError("Program can not be a null pointer; this operation will be discarded.");
		return;
	}

	_program = program;
	_set_uniforms = set_uniforms;
}

void
Node::set_name(std::string const& name)
{
	_name = std::string("Render ") + name;
}

size_t
Node::get_indices_nb() const
{
	return static_cast<size_t>(_indices_nb);
}

void
Node::set_indices_nb(size_t const& indices_nb)
{
	_indices_nb = static_cast<GLsizei>(indices_nb);
}

void
Node::add_texture(std::string const& name, GLuint tex_id, GLenum type)
{
	GLint max_combined_texture_image_units{-1};
	glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_combined_texture_image_units);
	std::size_t const max_active_texture_count
		= (max_combined_texture_image_units > 0) ? static_cast<std::size_t>(max_combined_texture_image_units)
		                                         : 80; // OpenGL 4.x guarantees at least 80.

	if (_textures.size() >= max_active_texture_count) {
		LogWarning("Trying to add more textures to an object than supported (%llu); the texture %s with ID %u will **not** be added. If you really need that many textures, do not use the `Node` class and roll your own solution instead.",
		           max_active_texture_count, name.c_str(), tex_id);
		return;
	}
	if (tex_id == 0u) {
		LogWarning("0 is not a valid texture ID; the texture %s (with ID %u) will **not** be added.",
		           name.c_str(), tex_id);
		return;
	}

	_textures.emplace_back(name, tex_id, type);
}

void
Node::add_child(Node const* child)
{
	if (child == nullptr) {
		LogWarning("Trying to add a null pointer as child: this will be discarded.");
		return;
	}

	_children.emplace_back(child);
}

size_t
Node::get_children_nb() const
{
	return _children.size();
}

Node const*
Node::get_child(size_t index) const
{
	assert(index < _children.size());
	return _children[index];
}

TRSTransformf const&
Node::get_transform() const
{
	return _transform;
}

TRSTransformf&
Node::get_transform()
{
	return _transform;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include "config.h"
#include "internal.h"
#include "couch_btree.h"
#include "reduces.h"
#include "bitfield.h"
#include "arena.h"
#include "tree_writer.h"
#include "node_types.h"
#include "util.h"

#include <stdlib.h>
#include <stdio.h>

typedef struct compact_ctx {
    TreeWriter* tree_writer;
    /* Using this for stuff that doesn't need to live longer than it takes to write
     * out a b-tree node (the k/v pairs) */
    arena *transient_arena;
    /* This is for stuff that lasts the duration of the b-tree writing (node pointers) */
    arena *persistent_arena;
    couchfile_modify_result *target_mr;
    Db* target;
    couchstore_compact_hook hook;
    couchstore_docinfo_hook dhook;
    void* hook_ctx;
    couchstore_compact_flags flags;
} compact_ctx;

static couchstore_error_t compact_seq_tree(Db* source, Db* target, compact_ctx *ctx);
static couchstore_error_t compact_localdocs_tree(Db* source, Db* target, compact_ctx *ctx);

couchstore_error_t couchstore_compact_db_ex(Db* source, const char* target_filename,
                                            couchstore_compact_flags flags,
                                            couchstore_compact_hook hook,
                                            couchstore_docinfo_hook dhook,
                                            void* hook_ctx,
                                            const couch_file_ops *ops)
{
    Db* target = NULL;
#ifdef WIN32
#define PATH_MAX MAX_PATH
#endif

#ifndef PATH_MAX
#define PATH_MAX 1024
#endif

    char tmpFile[PATH_MAX]; // keep this on the stack for duration of the call
    couchstore_error_t errcode;
    compact_ctx ctx = {NULL, new_arena(0), new_arena(0), NULL, NULL, hook, dhook, hook_ctx, 0};
    ctx.flags = flags;
    error_unless(!source->dropped, COUCHSTORE_ERROR_FILE_CLOSED);
    error_unless(ctx.transient_arena && ctx.persistent_arena, COUCHSTORE_ERROR_ALLOC_FAIL);

    error_pass(couchstore_open_db_ex(target_filename, COUCHSTORE_OPEN_FLAG_CREATE, ops, &target));

    ctx.target = target;
    target->file.pos = 1;
    target->header.update_seq = source->header.update_seq;
    if (flags & COUCHSTORE_COMPACT_FLAG_DROP_DELETES) {
        //Count the number of times purge has happened
        target->header.purge_seq = source->header.purge_seq + 1;
    } else {
        target->header.purge_seq = source->header.purge_seq;
    }
    target->header.purge_ptr = source->header.purge_ptr;

    if (source->header.by_seq_root) {
        strcpy(tmpFile, target_filename);
        strcat(tmpFile, ".btree-tmp_0");
        error_pass(TreeWriterOpen(tmpFile, ebin_cmp, by_id_reduce, by_id_rereduce, NULL, &ctx.tree_writer));
        error_pass(compact_seq_tree(source, target, &ctx));
        error_pass(TreeWriterSort(ctx.tree_writer));
        error_pass(TreeWriterWrite(ctx.tree_writer, &target->file, &target->header.by_id_root));
        TreeWriterFree(ctx.tree_writer);
        ctx.tree_writer = NULL;
    }

    if (source->header.local_docs_root) {
        error_pass(compact_localdocs_tree(source, target, &ctx));
    }
    if(ctx.hook != NULL) {
        error_pass(static_cast<couchstore_error_t>(ctx.hook(ctx.target, NULL, ctx.hook_ctx)));
    }
    error_pass(couchstore_commit(target));
cleanup:
    TreeWriterFree(ctx.tree_writer);
    delete_arena(ctx.transient_arena);
    delete_arena(ctx.persistent_arena);
    couchstore_close_db(target);
    if (errcode != COUCHSTORE_SUCCESS && target != NULL) {
        remove(target_filename);
    }
    return errcode;
}

couchstore_error_t couchstore_compact_db(Db* source, const char* target_filename)
{
    return couchstore_compact_db_ex(source, target_filename, 0, NULL, NULL, NULL,
                                    couchstore_get_default_file_ops());
}

static couchstore_error_t output_seqtree_item(const sized_buf *k,
                                              const sized_buf *v,
                                              const DocInfo *docinfo,
                                              compact_ctx *ctx)
{
    couchstore_error_t errcode = COUCHSTORE_SUCCESS;
    sized_buf *v_c;
    const raw_seq_index_value* rawSeq;
    uint32_t idsize, datasize;
    uint32_t revMetaSize;
    sized_buf id_k, id_v;
    raw_id_index_value *raw;
    sized_buf *k_c = arena_copy_buf(ctx->transient_arena, k);

    if (k_c == NULL) {
        error_pass(COUCHSTORE_ERROR_READ);
    }

    if (docinfo) {
        v_c = arena_special_copy_buf_and_revmeta(ctx->transient_arena,
                                                 v, docinfo);
    } else {
        v_c = arena_copy_buf(ctx->transient_arena, v);
    }

    if (v_c == NULL) {
        error_pass(COUCHSTORE_ERROR_READ);
    }

    error_pass(mr_push_item(k_c, v_c, ctx->target_mr));

    // Decode the by-sequence index value. See the file format doc or
    // assemble_id_index_value in couch_db.c:
    rawSeq = (const raw_seq_index_value*)v_c->buf;
    decode_kv_length(&rawSeq->sizes, &idsize, &datasize);
    revMetaSize = (uint32_t)v_c->size - (sizeof(raw_seq_index_value) + idsize);

    // Set up sized_bufs for the ID tree key and value:
    id_k.buf = (char*)(rawSeq + 1);
    id_k.size = idsize;
    id_v.size = sizeof(raw_id_index_value) + revMetaSize;
    id_v.buf = static_cast<char*>(arena_alloc(ctx->transient_arena, id_v.size));

    raw = (raw_id_index_value*)id_v.buf;
    raw->db_seq = *(raw_48*)k->buf;  //Copy db seq from seq tree key
    raw->size = encode_raw32(datasize);
    raw->bp = rawSeq->bp;
    raw->content_meta = rawSeq->content_meta;
    raw->rev_seq = rawSeq->rev_seq;
    memcpy(raw + 1, (uint8_t*)(rawSeq + 1) + idsize, revMetaSize); //Copy rev_meta

    error_pass(TreeWriterAddItem(ctx->tree_writer, id_k, id_v));

    if (ctx->target_mr->count == 0) {
        /* No items queued, we must have just flushed. We can safely rewind the transient arena. */
        arena_free_all(ctx->transient_arena);
    }

cleanup:
    return errcode;
}

static couchstore_error_t compact_seq_fetchcb(couchfile_lookup_request *rq,
                                              const sized_buf *k,
                                              const sized_buf *v)
{
    DocInfo* info = NULL;
    couchstore_error_t errcode = COUCHSTORE_SUCCESS;
    compact_ctx *ctx = (compact_ctx *) rq->callback_ctx;
    raw_seq_index_value* rawSeq = (raw_seq_index_value*)v->buf;
    uint64_t bpWithDeleted = decode_raw48(rawSeq->bp);
    uint64_t bp = bpWithDeleted & ~BP_DELETED_FLAG;
    int ret_val = 0;

    if ((bpWithDeleted & BP_DELETED_FLAG) &&
       (ctx->hook == NULL) &&
       (ctx->flags & COUCHSTORE_COMPACT_FLAG_DROP_DELETES)) {
        return COUCHSTORE_SUCCESS;
    }

    if(ctx->hook) {
        error_pass(by_seq_read_docinfo(&info, k, v));
        int hook_action = ctx->hook(ctx->target, info, ctx->hook_ctx);
        switch(hook_action) {
            case COUCHSTORE_COMPACT_KEEP_ITEM:
                break;
            case COUCHSTORE_COMPACT_DROP_ITEM:
                goto cleanup;
            default:
                error_pass(static_cast<couchstore_error_t>(hook_action));
        }
    }

    if (bp != 0) {
        cs_off_t new_bp = 0;
        // Copy the document from the old db file to the new one:
        size_t new_size = 0;
        sized_buf item;
        item.buf = NULL;

        int itemsize = pread_bin(rq->file, bp, &item.buf);
        if (itemsize < 0) {
            return static_cast<couchstore_error_t>(itemsize);
        }
        item.size = itemsize;

        if (ctx->dhook) {
            ret_val = ctx->dhook(&info, &item);
        }
        db_write_buf(ctx->target_mr->rq->file, &item, &new_bp, &new_size);

        bpWithDeleted = (bpWithDeleted & BP_DELETED_FLAG) | new_bp;  //Preserve high bit
        encode_raw48(bpWithDeleted, &rawSeq->bp);
        free(item.buf);
    }

    if (ret_val) {
        error_pass(output_seqtree_item(k, v, info, ctx));
    } else {
        error_pass(output_seqtree_item(k, v, NULL, ctx));
    }
cleanup:
    couchstore_free_docinfo(info);
    return errcode;
}

static couchstore_error_t compact_seq_tree(Db* source, Db* target, compact_ctx *ctx)
{
    couchstore_error_t errcode;
    compare_info seqcmp;
    seqcmp.compare = seq_cmp;
    couchfile_lookup_request srcfold;
    sized_buf low_key;
    //Keys in seq tree are 48-bit numbers, this is 0, lowest possible key
    low_key.buf = const_cast<char*>("\0\0\0\0\0\0");
    low_key.size = 6;
    sized_buf *low_key_list = &low_key;

    ctx->target_mr = new_btree_modres(ctx->persistent_arena, ctx->transient_arena, &target->file,
                                      &seqcmp, by_seq_reduce, by_seq_rereduce, NULL,
                                      DB_CHUNK_THRESHOLD, DB_CHUNK_THRESHOLD);
    if (ctx->target_mr == NULL) {
        error_pass(COUCHSTORE_ERROR_ALLOC_FAIL);
    }

    srcfold.cmp = seqcmp;
    srcfold.file = &source->file;
    srcfold.num_keys = 1;
    srcfold.keys = &low_key_list;
    srcfold.fold = 1;
    srcfold.in_fold = 1;
    srcfold.callback_ctx = ctx;
    srcfold.fetch_callback = compact_seq_fetchcb;
    srcfold.node_callback = NULL;

    errcode = btree_lookup(&srcfold, source->header.by_seq_root->pointer);
    if (errcode == COUCHSTORE_SUCCESS) {
        target->header.by_seq_root = complete_new_btree(ctx->target_mr, &errcode);
    }
cleanup:
    arena_free_all(ctx->persistent_arena);
    arena_free_all(ctx->transient_arena);
    return errcode;
}

static couchstore_error_t compact_localdocs_fetchcb(couchfile_lookup_request *rq,
                                                    const sized_buf *k,
                                                    const sized_buf *v)
{
    compact_ctx *ctx = (compact_ctx *) rq->callback_ctx;
    //printf("V: '%.*s'\n", v->size, v->buf);
    return mr_push_item(arena_copy_buf(ctx->persistent_arena, k),
                        arena_copy_buf(ctx->persistent_arena, v),
                        ctx->target_mr);
}

static couchstore_error_t compact_localdocs_tree(Db* source, Db* target, compact_ctx *ctx)
{
    couchstore_error_t errcode;
    compare_info idcmp;
    idcmp.compare = ebin_cmp;
    couchfile_lookup_request srcfold;

    sized_buf low_key;
    low_key.buf = NULL;
    low_key.size = 0;
    sized_buf *low_key_list = &low_key;

    ctx->target_mr = new_btree_modres(ctx->persistent_arena, NULL, &target->file,
                                      &idcmp, NULL, NULL, NULL, DB_CHUNK_THRESHOLD,
                                      DB_CHUNK_THRESHOLD);
    if (ctx->target_mr == NULL) {
        error_pass(COUCHSTORE_ERROR_ALLOC_FAIL);
    }

    srcfold.cmp = idcmp;
    srcfold.file = &source->file;
    srcfold.num_keys = 1;
    srcfold.keys = &low_key_list;
    srcfold.fold = 1;
    srcfold.in_fold = 1;
    srcfold.callback_ctx = ctx;
    srcfold.fetch_callback = compact_localdocs_fetchcb;
    srcfold.node_callback = NULL;

    errcode = btree_lookup(&srcfold, source->header.local_docs_root->pointer);
    if (errcode == COUCHSTORE_SUCCESS) {
        target->header.local_docs_root = complete_new_btree(ctx->target_mr, &errcode);
    }
cleanup:
    arena_free_all(ctx->persistent_arena);
    return errcode;
}

couchstore_error_t couchstore_set_purge_seq(Db* target, uint64_t purge_seq) {
    target->header.purge_seq = purge_seq;
    return COUCHSTORE_SUCCESS;

}

<commit_msg>MB-11845: Handle couchstore_open_db_ex's failure scenario<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include "config.h"
#include "internal.h"
#include "couch_btree.h"
#include "reduces.h"
#include "bitfield.h"
#include "arena.h"
#include "tree_writer.h"
#include "node_types.h"
#include "util.h"

#include <stdlib.h>
#include <stdio.h>

typedef struct compact_ctx {
    TreeWriter* tree_writer;
    /* Using this for stuff that doesn't need to live longer than it takes to write
     * out a b-tree node (the k/v pairs) */
    arena *transient_arena;
    /* This is for stuff that lasts the duration of the b-tree writing (node pointers) */
    arena *persistent_arena;
    couchfile_modify_result *target_mr;
    Db* target;
    couchstore_compact_hook hook;
    couchstore_docinfo_hook dhook;
    void* hook_ctx;
    couchstore_compact_flags flags;
} compact_ctx;

static couchstore_error_t compact_seq_tree(Db* source, Db* target, compact_ctx *ctx);
static couchstore_error_t compact_localdocs_tree(Db* source, Db* target, compact_ctx *ctx);

couchstore_error_t couchstore_compact_db_ex(Db* source, const char* target_filename,
                                            couchstore_compact_flags flags,
                                            couchstore_compact_hook hook,
                                            couchstore_docinfo_hook dhook,
                                            void* hook_ctx,
                                            const couch_file_ops *ops)
{
    Db* target = NULL;
#ifdef WIN32
#define PATH_MAX MAX_PATH
#endif

#ifndef PATH_MAX
#define PATH_MAX 1024
#endif

    char tmpFile[PATH_MAX]; // keep this on the stack for duration of the call
    couchstore_error_t errcode;
    compact_ctx ctx = {NULL, new_arena(0), new_arena(0), NULL, NULL, hook, dhook, hook_ctx, 0};
    ctx.flags = flags;
    error_unless(!source->dropped, COUCHSTORE_ERROR_FILE_CLOSED);
    error_unless(ctx.transient_arena && ctx.persistent_arena, COUCHSTORE_ERROR_ALLOC_FAIL);

    error_pass(couchstore_open_db_ex(target_filename, COUCHSTORE_OPEN_FLAG_CREATE, ops, &target));

    ctx.target = target;
    target->file.pos = 1;
    target->header.update_seq = source->header.update_seq;
    if (flags & COUCHSTORE_COMPACT_FLAG_DROP_DELETES) {
        //Count the number of times purge has happened
        target->header.purge_seq = source->header.purge_seq + 1;
    } else {
        target->header.purge_seq = source->header.purge_seq;
    }
    target->header.purge_ptr = source->header.purge_ptr;

    if (source->header.by_seq_root) {
        strcpy(tmpFile, target_filename);
        strcat(tmpFile, ".btree-tmp_0");
        error_pass(TreeWriterOpen(tmpFile, ebin_cmp, by_id_reduce, by_id_rereduce, NULL, &ctx.tree_writer));
        error_pass(compact_seq_tree(source, target, &ctx));
        error_pass(TreeWriterSort(ctx.tree_writer));
        error_pass(TreeWriterWrite(ctx.tree_writer, &target->file, &target->header.by_id_root));
        TreeWriterFree(ctx.tree_writer);
        ctx.tree_writer = NULL;
    }

    if (source->header.local_docs_root) {
        error_pass(compact_localdocs_tree(source, target, &ctx));
    }
    if(ctx.hook != NULL) {
        error_pass(static_cast<couchstore_error_t>(ctx.hook(ctx.target, NULL, ctx.hook_ctx)));
    }
    error_pass(couchstore_commit(target));
cleanup:
    TreeWriterFree(ctx.tree_writer);
    delete_arena(ctx.transient_arena);
    delete_arena(ctx.persistent_arena);
    if (target != NULL) {
        couchstore_close_db(target);
        if (errcode != COUCHSTORE_SUCCESS) {
            remove(target_filename);
        }
    }
    return errcode;
}

couchstore_error_t couchstore_compact_db(Db* source, const char* target_filename)
{
    return couchstore_compact_db_ex(source, target_filename, 0, NULL, NULL, NULL,
                                    couchstore_get_default_file_ops());
}

static couchstore_error_t output_seqtree_item(const sized_buf *k,
                                              const sized_buf *v,
                                              const DocInfo *docinfo,
                                              compact_ctx *ctx)
{
    couchstore_error_t errcode = COUCHSTORE_SUCCESS;
    sized_buf *v_c;
    const raw_seq_index_value* rawSeq;
    uint32_t idsize, datasize;
    uint32_t revMetaSize;
    sized_buf id_k, id_v;
    raw_id_index_value *raw;
    sized_buf *k_c = arena_copy_buf(ctx->transient_arena, k);

    if (k_c == NULL) {
        error_pass(COUCHSTORE_ERROR_READ);
    }

    if (docinfo) {
        v_c = arena_special_copy_buf_and_revmeta(ctx->transient_arena,
                                                 v, docinfo);
    } else {
        v_c = arena_copy_buf(ctx->transient_arena, v);
    }

    if (v_c == NULL) {
        error_pass(COUCHSTORE_ERROR_READ);
    }

    error_pass(mr_push_item(k_c, v_c, ctx->target_mr));

    // Decode the by-sequence index value. See the file format doc or
    // assemble_id_index_value in couch_db.c:
    rawSeq = (const raw_seq_index_value*)v_c->buf;
    decode_kv_length(&rawSeq->sizes, &idsize, &datasize);
    revMetaSize = (uint32_t)v_c->size - (sizeof(raw_seq_index_value) + idsize);

    // Set up sized_bufs for the ID tree key and value:
    id_k.buf = (char*)(rawSeq + 1);
    id_k.size = idsize;
    id_v.size = sizeof(raw_id_index_value) + revMetaSize;
    id_v.buf = static_cast<char*>(arena_alloc(ctx->transient_arena, id_v.size));

    raw = (raw_id_index_value*)id_v.buf;
    raw->db_seq = *(raw_48*)k->buf;  //Copy db seq from seq tree key
    raw->size = encode_raw32(datasize);
    raw->bp = rawSeq->bp;
    raw->content_meta = rawSeq->content_meta;
    raw->rev_seq = rawSeq->rev_seq;
    memcpy(raw + 1, (uint8_t*)(rawSeq + 1) + idsize, revMetaSize); //Copy rev_meta

    error_pass(TreeWriterAddItem(ctx->tree_writer, id_k, id_v));

    if (ctx->target_mr->count == 0) {
        /* No items queued, we must have just flushed. We can safely rewind the transient arena. */
        arena_free_all(ctx->transient_arena);
    }

cleanup:
    return errcode;
}

static couchstore_error_t compact_seq_fetchcb(couchfile_lookup_request *rq,
                                              const sized_buf *k,
                                              const sized_buf *v)
{
    DocInfo* info = NULL;
    couchstore_error_t errcode = COUCHSTORE_SUCCESS;
    compact_ctx *ctx = (compact_ctx *) rq->callback_ctx;
    raw_seq_index_value* rawSeq = (raw_seq_index_value*)v->buf;
    uint64_t bpWithDeleted = decode_raw48(rawSeq->bp);
    uint64_t bp = bpWithDeleted & ~BP_DELETED_FLAG;
    int ret_val = 0;

    if ((bpWithDeleted & BP_DELETED_FLAG) &&
       (ctx->hook == NULL) &&
       (ctx->flags & COUCHSTORE_COMPACT_FLAG_DROP_DELETES)) {
        return COUCHSTORE_SUCCESS;
    }

    if(ctx->hook) {
        error_pass(by_seq_read_docinfo(&info, k, v));
        int hook_action = ctx->hook(ctx->target, info, ctx->hook_ctx);
        switch(hook_action) {
            case COUCHSTORE_COMPACT_KEEP_ITEM:
                break;
            case COUCHSTORE_COMPACT_DROP_ITEM:
                goto cleanup;
            default:
                error_pass(static_cast<couchstore_error_t>(hook_action));
        }
    }

    if (bp != 0) {
        cs_off_t new_bp = 0;
        // Copy the document from the old db file to the new one:
        size_t new_size = 0;
        sized_buf item;
        item.buf = NULL;

        int itemsize = pread_bin(rq->file, bp, &item.buf);
        if (itemsize < 0) {
            return static_cast<couchstore_error_t>(itemsize);
        }
        item.size = itemsize;

        if (ctx->dhook) {
            ret_val = ctx->dhook(&info, &item);
        }
        db_write_buf(ctx->target_mr->rq->file, &item, &new_bp, &new_size);

        bpWithDeleted = (bpWithDeleted & BP_DELETED_FLAG) | new_bp;  //Preserve high bit
        encode_raw48(bpWithDeleted, &rawSeq->bp);
        free(item.buf);
    }

    if (ret_val) {
        error_pass(output_seqtree_item(k, v, info, ctx));
    } else {
        error_pass(output_seqtree_item(k, v, NULL, ctx));
    }
cleanup:
    couchstore_free_docinfo(info);
    return errcode;
}

static couchstore_error_t compact_seq_tree(Db* source, Db* target, compact_ctx *ctx)
{
    couchstore_error_t errcode;
    compare_info seqcmp;
    seqcmp.compare = seq_cmp;
    couchfile_lookup_request srcfold;
    sized_buf low_key;
    //Keys in seq tree are 48-bit numbers, this is 0, lowest possible key
    low_key.buf = const_cast<char*>("\0\0\0\0\0\0");
    low_key.size = 6;
    sized_buf *low_key_list = &low_key;

    ctx->target_mr = new_btree_modres(ctx->persistent_arena, ctx->transient_arena, &target->file,
                                      &seqcmp, by_seq_reduce, by_seq_rereduce, NULL,
                                      DB_CHUNK_THRESHOLD, DB_CHUNK_THRESHOLD);
    if (ctx->target_mr == NULL) {
        error_pass(COUCHSTORE_ERROR_ALLOC_FAIL);
    }

    srcfold.cmp = seqcmp;
    srcfold.file = &source->file;
    srcfold.num_keys = 1;
    srcfold.keys = &low_key_list;
    srcfold.fold = 1;
    srcfold.in_fold = 1;
    srcfold.callback_ctx = ctx;
    srcfold.fetch_callback = compact_seq_fetchcb;
    srcfold.node_callback = NULL;

    errcode = btree_lookup(&srcfold, source->header.by_seq_root->pointer);
    if (errcode == COUCHSTORE_SUCCESS) {
        target->header.by_seq_root = complete_new_btree(ctx->target_mr, &errcode);
    }
cleanup:
    arena_free_all(ctx->persistent_arena);
    arena_free_all(ctx->transient_arena);
    return errcode;
}

static couchstore_error_t compact_localdocs_fetchcb(couchfile_lookup_request *rq,
                                                    const sized_buf *k,
                                                    const sized_buf *v)
{
    compact_ctx *ctx = (compact_ctx *) rq->callback_ctx;
    //printf("V: '%.*s'\n", v->size, v->buf);
    return mr_push_item(arena_copy_buf(ctx->persistent_arena, k),
                        arena_copy_buf(ctx->persistent_arena, v),
                        ctx->target_mr);
}

static couchstore_error_t compact_localdocs_tree(Db* source, Db* target, compact_ctx *ctx)
{
    couchstore_error_t errcode;
    compare_info idcmp;
    idcmp.compare = ebin_cmp;
    couchfile_lookup_request srcfold;

    sized_buf low_key;
    low_key.buf = NULL;
    low_key.size = 0;
    sized_buf *low_key_list = &low_key;

    ctx->target_mr = new_btree_modres(ctx->persistent_arena, NULL, &target->file,
                                      &idcmp, NULL, NULL, NULL, DB_CHUNK_THRESHOLD,
                                      DB_CHUNK_THRESHOLD);
    if (ctx->target_mr == NULL) {
        error_pass(COUCHSTORE_ERROR_ALLOC_FAIL);
    }

    srcfold.cmp = idcmp;
    srcfold.file = &source->file;
    srcfold.num_keys = 1;
    srcfold.keys = &low_key_list;
    srcfold.fold = 1;
    srcfold.in_fold = 1;
    srcfold.callback_ctx = ctx;
    srcfold.fetch_callback = compact_localdocs_fetchcb;
    srcfold.node_callback = NULL;

    errcode = btree_lookup(&srcfold, source->header.local_docs_root->pointer);
    if (errcode == COUCHSTORE_SUCCESS) {
        target->header.local_docs_root = complete_new_btree(ctx->target_mr, &errcode);
    }
cleanup:
    arena_free_all(ctx->persistent_arena);
    return errcode;
}

couchstore_error_t couchstore_set_purge_seq(Db* target, uint64_t purge_seq) {
    target->header.purge_seq = purge_seq;
    return COUCHSTORE_SUCCESS;

}

<|endoftext|>


<commit_before>/*****************************************************************************
 * Author:   Valient Gough <vgough@pobox.com>
 *
 *****************************************************************************
 * Copyright (c) 2002-2003, Valient Gough
 *
 * This library is free software; you can distribute it and/or modify it under
 * the terms of the GNU Lesser General Public License (LGPL), as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the LGPL in the file COPYING for more
 * details.
 *
 */

#include <cstring>

#include "RLogChannel.h"
#include "rlog.h"
#include "Lock.h"

using namespace std;
using namespace rlog;

const char GlobalComponent[] = "/";

namespace rlog
{
    static RLogChannel *gRootChannel =0;

    // big lock around channel lookups..
    static Mutex gChannelLock;

    // Use GetComponentChannel here because we want to reference the global
    // versions, not the componentized versions..
    // We'll use
    RLogChannel *_RLDebugChannel = GetGlobalChannel( "debug", Log_Debug );
    RLogChannel *_RLInfoChannel = GetGlobalChannel( "info", Log_Info );
    RLogChannel *_RLWarningChannel = GetGlobalChannel( "warning", Log_Warning );
    RLogChannel *_RLErrorChannel = GetGlobalChannel( "error", Log_Error );
}

/*! @class rlog::RLogChannel <rlog/RLogChannel.h>
  @brief Implements a hierarchical logging channel

  You should not need to use RLogChannel directly under normal
  circumstances. See RLOG_CHANNEL() macro, GetComponentChannel() and
  GetGlobalChannel()

  RLogChannel implements channel logging support.  A channel is a named
  logging location which is global to the program.  Channels are
  hierarchically related.

  For example, if somewhere in your program a message is logged to
  "debug/foo/bar", then it will be delived to any subscribers to
  "debug/foo/bar", or subscribers to "debug/foo", or subscribers to
  "debug".   Subscribing to a channel means you will receive anything
  published on that channel or sub-channels.

  As a special case, subscribing to the channel "" means you will receive
  all messages - as every message has a channel and the empty string "" is
  considered to mean the root of the channel tree.

  In addition, componentized channels are all considered sub channels of
  the global channel hierarchy.  All rDebug(), rWarning(), and rError()
  macros publish to the componentized channels (component defined by
  RLOG_COMPONENT).

  @code
      // get the "debug" channel for our component.  This is the same as
      // what rDebug() publishes to.
      RLogChannel *node = RLOG_CHANNEL( "debug", Log_Debug );
      // equivalent to
      RLogChannel *node = GetComponentChannel( RLOG_COMPONENT, "debug" );

      // Or, get the global "debug" channel, which will have messages from
      // *all* component's "debug" channels.
      RLogChannel *node = GetGlobalChannel( "debug", Log_Debug );
  @endcode

  @author Valient Gough
  @see RLOG_CHANNEL()
  @see GetComponentChannel()
  @see GetGlobalChannel()
*/

RLogChannel::RLogChannel( const string &n, LogLevel level )
    : RLogNode()
    , _name( n )
    , _level( level )
{
}

RLogChannel::~RLogChannel()
{
}

const std::string &RLogChannel::name() const
{
    return _name;
}

LogLevel RLogChannel::logLevel() const
{
    return _level;
}

void RLogChannel::setLogLevel(LogLevel level)
{
    _level = level;
}

RLogChannel *RLogChannel::getComponent( RLogChannel *parent,
	const char *component )
{
    ComponentMap::const_iterator it = components.find( component );
    if(it == components.end())
    {
	RLogChannel *ch = new RLogChannel( _name, _level );
	components.insert( make_pair( component, ch ) );

	// connect to its parent
	if(parent)
	    parent->addPublisher( ch );

	// connect to globalized version
	addPublisher( ch );

	return ch;
    } else
    {
	return it->second;
    }
}

/*! @relates RLogChannel
  @brief Return the named channel across all components.

  Channels are hierarchical.  See RLogChannel for more detail.
  The global channel contains messages for all component channels.

  For example, subscribing to the global "debug" means the subscriber would
  also get messages from <Component , "debug">, and <Component-B, "debug">, and
  <Component-C, "debug/foo">, etc.

  @author Valient Gough
*/
RLogChannel *rlog::GetGlobalChannel( const char *path, LogLevel level )
{
    return GetComponentChannel( GlobalComponent, path, level );
}

/*!  @relates RLogChannel
  @brief Return the named channel for a particular component.

  @author Valient Gough
*/
RLogChannel *rlog::GetComponentChannel( const char *component,
	const char *path, LogLevel level )
{
    // since we much with the globally visible channel tree, hold a lock..
    Lock lock( &gChannelLock );

    string currentPath;

    if(!gRootChannel)
	gRootChannel = new RLogChannel( "", level );

    RLogChannel *current = gRootChannel;
    RLogChannel *currentComponent = 0;
    if(strcmp( component, GlobalComponent ) != 0)
	currentComponent = gRootChannel->getComponent( 0, component );

    while( *path )
    {
	// if log level is currently undefined but we now know what it is, then
	// define it..
	if((current->logLevel() == Log_Undef) && (level != Log_Undef))
	    current->setLogLevel( level );

	const char *next = strchr( path , '/' );
	size_t len = next ? next - path : strlen( path );

	if(len > 1)
	{
	    string pathEl( path, len );

	    if(!currentPath.empty())
		currentPath += '/';
	    currentPath += pathEl;

	    ComponentMap::const_iterator it =
		current->subChannels.find( pathEl );
	    if(it != current->subChannels.end())
	    {
		// found.  possibly creating sub-map
		current = it->second;
	    } else
	    {
		// create
		RLogChannel *nm = new RLogChannel( currentPath, level );
		current->subChannels.insert( make_pair(pathEl, nm) );

		current->addPublisher( nm );

		current = nm;
	    }
	    // track componentized version
	    if(currentComponent)
    		currentComponent = current->getComponent( currentComponent,
			component );

	    path += len;
	} else
	{
	    // skip separator character
	    ++path;
	}
    }

    if(currentComponent)
	return currentComponent;
    else
	return current;
}

void
RLogChannel::publish(const RLogData &data)
{
    set< RLogNode* >::const_iterator it = data.seen.find( this );
    if(it == data.seen.end())
    {
	const_cast<RLogData&>(data).seen.insert( this );
	RLogNode::publish( data );
    }
}

<commit_msg>fix off-by-one which cause single-char paths to be ignored.  fixes issue #10<commit_after>/*****************************************************************************
 * Author:   Valient Gough <vgough@pobox.com>
 *
 *****************************************************************************
 * Copyright (c) 2002-2003, Valient Gough
 *
 * This library is free software; you can distribute it and/or modify it under
 * the terms of the GNU Lesser General Public License (LGPL), as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the LGPL in the file COPYING for more
 * details.
 *
 */

#include <cstring>

#include "RLogChannel.h"
#include "rlog.h"
#include "Lock.h"

using namespace std;
using namespace rlog;

const char GlobalComponent[] = "/";

namespace rlog
{
    static RLogChannel *gRootChannel =0;

    // big lock around channel lookups..
    static Mutex gChannelLock;

    // Use GetComponentChannel here because we want to reference the global
    // versions, not the componentized versions..
    // We'll use
    RLogChannel *_RLDebugChannel = GetGlobalChannel( "debug", Log_Debug );
    RLogChannel *_RLInfoChannel = GetGlobalChannel( "info", Log_Info );
    RLogChannel *_RLWarningChannel = GetGlobalChannel( "warning", Log_Warning );
    RLogChannel *_RLErrorChannel = GetGlobalChannel( "error", Log_Error );
}

/*! @class rlog::RLogChannel <rlog/RLogChannel.h>
  @brief Implements a hierarchical logging channel

  You should not need to use RLogChannel directly under normal
  circumstances. See RLOG_CHANNEL() macro, GetComponentChannel() and
  GetGlobalChannel()

  RLogChannel implements channel logging support.  A channel is a named
  logging location which is global to the program.  Channels are
  hierarchically related.

  For example, if somewhere in your program a message is logged to
  "debug/foo/bar", then it will be delived to any subscribers to
  "debug/foo/bar", or subscribers to "debug/foo", or subscribers to
  "debug".   Subscribing to a channel means you will receive anything
  published on that channel or sub-channels.

  As a special case, subscribing to the channel "" means you will receive
  all messages - as every message has a channel and the empty string "" is
  considered to mean the root of the channel tree.

  In addition, componentized channels are all considered sub channels of
  the global channel hierarchy.  All rDebug(), rWarning(), and rError()
  macros publish to the componentized channels (component defined by
  RLOG_COMPONENT).

  @code
      // get the "debug" channel for our component.  This is the same as
      // what rDebug() publishes to.
      RLogChannel *node = RLOG_CHANNEL( "debug", Log_Debug );
      // equivalent to
      RLogChannel *node = GetComponentChannel( RLOG_COMPONENT, "debug" );

      // Or, get the global "debug" channel, which will have messages from
      // *all* component's "debug" channels.
      RLogChannel *node = GetGlobalChannel( "debug", Log_Debug );
  @endcode

  @author Valient Gough
  @see RLOG_CHANNEL()
  @see GetComponentChannel()
  @see GetGlobalChannel()
*/

RLogChannel::RLogChannel( const string &n, LogLevel level )
    : RLogNode()
    , _name( n )
    , _level( level )
{
}

RLogChannel::~RLogChannel()
{
}

const std::string &RLogChannel::name() const
{
    return _name;
}

LogLevel RLogChannel::logLevel() const
{
    return _level;
}

void RLogChannel::setLogLevel(LogLevel level)
{
    _level = level;
}

RLogChannel *RLogChannel::getComponent( RLogChannel *parent,
	const char *component )
{
    ComponentMap::const_iterator it = components.find( component );
    if(it == components.end())
    {
	RLogChannel *ch = new RLogChannel( _name, _level );
	components.insert( make_pair( component, ch ) );

	// connect to its parent
	if(parent)
	    parent->addPublisher( ch );

	// connect to globalized version
	addPublisher( ch );

	return ch;
    } else
    {
	return it->second;
    }
}

/*! @relates RLogChannel
  @brief Return the named channel across all components.

  Channels are hierarchical.  See RLogChannel for more detail.
  The global channel contains messages for all component channels.

  For example, subscribing to the global "debug" means the subscriber would
  also get messages from <Component , "debug">, and <Component-B, "debug">, and
  <Component-C, "debug/foo">, etc.

  @author Valient Gough
*/
RLogChannel *rlog::GetGlobalChannel( const char *path, LogLevel level )
{
    return GetComponentChannel( GlobalComponent, path, level );
}

/*!  @relates RLogChannel
  @brief Return the named channel for a particular component.

  @author Valient Gough
*/
RLogChannel *rlog::GetComponentChannel( const char *component,
	const char *path, LogLevel level )
{
    // since we much with the globally visible channel tree, hold a lock..
    Lock lock( &gChannelLock );

    string currentPath;

    if(!gRootChannel)
	gRootChannel = new RLogChannel( "", level );

    RLogChannel *current = gRootChannel;
    RLogChannel *currentComponent = 0;
    if(strcmp( component, GlobalComponent ) != 0)
	currentComponent = gRootChannel->getComponent( 0, component );

    while( *path )
    {
	// if log level is currently undefined but we now know what it is, then
	// define it..
	if((current->logLevel() == Log_Undef) && (level != Log_Undef))
	    current->setLogLevel( level );

	const char *next = strchr( path , '/' );
	size_t len = next ? next - path : strlen( path );

	if(len >= 1)
	{
	    string pathEl( path, len );

	    if(!currentPath.empty())
		currentPath += '/';
	    currentPath += pathEl;

	    ComponentMap::const_iterator it =
		current->subChannels.find( pathEl );
	    if(it != current->subChannels.end())
	    {
		// found.  possibly creating sub-map
		current = it->second;
	    } else
	    {
		// create
		RLogChannel *nm = new RLogChannel( currentPath, level );
		current->subChannels.insert( make_pair(pathEl, nm) );

		current->addPublisher( nm );

		current = nm;
	    }
	    // track componentized version
	    if(currentComponent)
    		currentComponent = current->getComponent( currentComponent,
			component );

	    path += len;
	} else
	{
	    // skip separator character
	    ++path;
	}
    }

    if(currentComponent)
	return currentComponent;
    else
	return current;
}

void
RLogChannel::publish(const RLogData &data)
{
    set< RLogNode* >::const_iterator it = data.seen.find( this );
    if(it == data.seen.end())
    {
	const_cast<RLogData&>(data).seen.insert( this );
	RLogNode::publish( data );
    }
}

<|endoftext|>


<commit_before>AliAnalysisTask *AddTaskFlowd(Bool_t fillTree = kFALSE){

  //get the current analysis manager
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTaskFlowd", "No analysis manager found.");
    return 0;
  }

  // Check the analysis type using the event handlers connected to the analysis manager.
   //==============================================================================
   if (!mgr->GetInputEventHandler()) {
      ::Error("AddTaskFlowd", "This task requires an input event handler");
      return NULL;
   }

  //========= Add task to the ANALYSIS manager =====
  AliAnalysisTaskFlowd *task = new AliAnalysisTaskFlowd("Flowd");

  //Int_t iResult = task->Initialize();
  // if (!iResult)
  mgr->AddTask(task);
    // else {
    //AliError("NO pt ranges specfied, not adding the task !!!");
    //return -1;
    //}

  //mgr->AddTask(task);

  //================================================
  //              data containers
  //================================================
  //            find input container
  //below the trunk version
  //AliAnalysisDataContainer *cinput  = mgr->GetCommonInputContainer();

  //dumm output container
  // AliAnalysisDataContainer *coutput0 =
  //     mgr->CreateContainer("mpuccio_treeFlowd",
  //                          TTree::Class(),
  //                          AliAnalysisManager::kExchangeContainer,
  //                          "mpuccio_default");

  //define output containers, please use 'username'_'somename'
  AliAnalysisDataContainer *coutput1 =
      mgr->CreateContainer("mpuccio_Flowd", TList::Class(),AliAnalysisManager::kOutputContainer,"mpuccio_Flowd.root");

  //connect containers
  mgr->ConnectInput  (task,  0,  mgr->GetCommonInputContainer());
  //mgr->ConnectOutput (task,  0, coutput0);
  mgr->ConnectOutput (task,  1, coutput1);
  task->SetFillTree(fillTree);
  if (fillTree) {
    AliAnalysisDataContainer *coutput2 = mgr->CreateContainer("mpuccio_FlowdTree", TTree::Class(),
                                                              AliAnalysisManager::kOutputContainer,
                                                              "mpuccio_Flowd_tree.root");
    coutput2->SetSpecialOutput();
    mgr->ConnectOutput (task,  2, coutput2);
  }

  return task;
}
<commit_msg>The Ntuple is not in a separate output now<commit_after>AliAnalysisTask *AddTaskFlowd(Bool_t fillTree = kFALSE){

  //get the current analysis manager
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTaskFlowd", "No analysis manager found.");
    return 0;
  }

  // Check the analysis type using the event handlers connected to the analysis manager.
   //==============================================================================
   if (!mgr->GetInputEventHandler()) {
      ::Error("AddTaskFlowd", "This task requires an input event handler");
      return NULL;
   }

  //========= Add task to the ANALYSIS manager =====
  AliAnalysisTaskFlowd *task = new AliAnalysisTaskFlowd("Flowd");

  //Int_t iResult = task->Initialize();
  // if (!iResult)
  mgr->AddTask(task);
    // else {
    //AliError("NO pt ranges specfied, not adding the task !!!");
    //return -1;
    //}

  //mgr->AddTask(task);

  //================================================
  //              data containers
  //================================================
  //            find input container
  //below the trunk version
  //AliAnalysisDataContainer *cinput  = mgr->GetCommonInputContainer();

  //dumm output container
  // AliAnalysisDataContainer *coutput0 =
  //     mgr->CreateContainer("mpuccio_treeFlowd",
  //                          TTree::Class(),
  //                          AliAnalysisManager::kExchangeContainer,
  //                          "mpuccio_default");

  //define output containers, please use 'username'_'somename'
  AliAnalysisDataContainer *coutput1 =
      mgr->CreateContainer("mpuccio_Flowd", TList::Class(),AliAnalysisManager::kOutputContainer,"mpuccio_Flowd.root");

  //connect containers
  mgr->ConnectInput  (task,  0,  mgr->GetCommonInputContainer());
  //mgr->ConnectOutput (task,  0, coutput0);
  mgr->ConnectOutput (task,  1, coutput1);
  task->SetFillTree(fillTree);
//  if (fillTree) {
//    AliAnalysisDataContainer *coutput2 = mgr->CreateContainer("mpuccio_FlowdTree", TNtuple::Class(),
//                                                              AliAnalysisManager::kOutputContainer,
//                                                              "mpuccio_Flowd_tree.root");
//    coutput2->SetSpecialOutput();
//    mgr->ConnectOutput (task,  2, coutput2);
//  }

  return task;
}
<|endoftext|>