text:
/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include <bitset>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>

#include <db/db.h>
#include <base/util.h>
#include <base/string_util.h>

#include <cmn/agent_cmn.h>
#include <init/agent_param.h>
#include <boost/functional/factory.hpp>
#include <cmn/agent_factory.h>
#include <oper/interface_common.h>
#include <oper/mirror_table.h>
#include <oper/global_vrouter.h>

#include <ksync/ksync_index.h>
#include <ksync/ksync_entry.h>
#include <ksync/ksync_object.h>
#include <ksync/ksync_netlink.h>
#include <ksync/ksync_sock.h>
#include <uve/agent_uve.h>
#include <vrouter/flow_stats/flow_stats_collector.h>
#include <uve/vn_uve_table.h>
#include <uve/vm_uve_table.h>
#include <uve/interface_uve_stats_table.h>
#include <uve/vrouter_uve_entry.h>
#include <algorithm>
#include <pkt/flow_proto.h>
#include <pkt/flow_mgmt.h>
#include <vrouter/ksync/ksync_init.h>
#include <vrouter/flow_stats/flow_stats_types.h>

bool flow_ageing_debug_ = false;
FlowStatsCollector::FlowStatsCollector(boost::asio::io_service &io, int intvl,
                                       uint32_t flow_cache_timeout,
                                       AgentUveBase *uve,
                                       uint32_t instance_id,
                                       FlowAgingTableKey *key,
                                       FlowStatsManager *aging_module,
                                       FlowStatsCollectorObject *obj) :
        StatsCollector(TaskScheduler::GetInstance()->GetTaskId
                       (kTaskFlowStatsCollector), instance_id,
                       io, kFlowStatsTimerInterval, "Flow stats collector"),
        agent_uve_(uve),
        task_id_(uve->agent()->task_scheduler()->GetTaskId
                 (kTaskFlowStatsCollector)),
        rand_gen_(boost::uuids::random_generator()),
        flow_iteration_key_(NULL),
        entries_to_visit_(0),
        flow_tcp_syn_age_time_(FlowTcpSynAgeTime),
        retry_delete_(true),
        request_queue_(agent_uve_->agent()->task_scheduler()->
                       GetTaskId(kTaskFlowStatsCollector),
                       instance_id,
                       boost::bind(&FlowStatsCollector::RequestHandler,
                                   this, _1)),
        msg_list_(kMaxFlowMsgsPerSend, FlowLogData()), msg_index_(0),
        flow_aging_key_(*key), instance_id_(instance_id),
        flow_stats_manager_(aging_module), parent_(obj), ageing_task_(NULL),
        current_time_(GetCurrentTime()), ageing_task_starts_(0) {
        if (flow_cache_timeout) {
            // Convert to usec
            flow_age_time_intvl_ = 1000000L * (uint64_t)flow_cache_timeout;
        } else {
            flow_age_time_intvl_ = FlowAgeTime;
        }
        deleted_ = false;
        request_queue_.set_name("Flow stats collector");
        request_queue_.set_measure_busy_time
            (agent_uve_->agent()->MeasureQueueDelay());
        request_queue_.SetEntryCallback
            (boost::bind(&FlowStatsCollector::RequestHandlerEntry, this));
        request_queue_.SetExitCallback
            (boost::bind(&FlowStatsCollector::RequestHandlerExit, this, _1));
        // Aging timer fires every kFlowStatsTimerInterval msec. Compute
        // number of timer fires needed to scan complete table
        timers_per_scan_ = TimersPerScan();
}

FlowStatsCollector::~FlowStatsCollector() {
    flow_stats_manager_->FreeIndex(instance_id_);
}

boost::uuids::uuid FlowStatsCollector::rand_gen() {
    return rand_gen_();
}

uint64_t FlowStatsCollector::GetCurrentTime() {
    return UTCTimestampUsec();
}

void FlowStatsCollector::Shutdown() {
    assert(ageing_task_ == NULL);
    StatsCollector::Shutdown();
    request_queue_.Shutdown();
}

// We want to scan the flow table every 25% of configured ageing time.
// Compute number of timer fires needed to scan the flow-table once.
uint32_t FlowStatsCollector::TimersPerScan() {
    uint64_t scan_time_millisec;
    /* Use Age Time itself as scan-time for flows */

    // Convert aging-time configured in micro-sec to millisecond
    scan_time_millisec = flow_age_time_intvl_ / 1000;

    // Compute time in which we must scan the complete table to honor the
    // kFlowScanTime
    scan_time_millisec = (scan_time_millisec * kFlowScanTime) / 100;

    // Enforce min value on scan-time
    if (scan_time_millisec < kFlowStatsTimerInterval) {
        scan_time_millisec = kFlowStatsTimerInterval;
    }

    // Number of timer fires needed to scan table once
    return scan_time_millisec / kFlowStatsTimerInterval;
}

// Update entries_to_visit_ based on total flows
// Timer fires every kFlowScanTime. Its possible that we may not have visited
// all entries by the time next timer fires. So, keep accumulating the number
// of entries to visit into entries_to_visit_
//
// A lower-bound and an upper-bound are enforced on entries_to_visit_
void FlowStatsCollector::UpdateEntriesToVisit() {
    // Compute number of flows to visit per scan-time
    uint32_t count = flow_export_info_list_.size();
    uint32_t entries = count / timers_per_scan_;

    // Update number of entries to visit in flow.
    // The scan for previous timer may still be in progress. So, accmulate
    // number of entries to visit
    entries_to_visit_ += entries;

    // Cap number of entries to visit to 25% of table
    if (entries_to_visit_ > ((count * kFlowScanTime)/100))
        entries_to_visit_ = (count * kFlowScanTime)/100;

    // Apply lower-limit
    if (entries_to_visit_ < kMinFlowsPerTimer)
        entries_to_visit_ = kMinFlowsPerTimer;

    return;
}

bool FlowStatsCollector::ShouldBeAged(FlowExportInfo *info,
                                      const vr_flow_entry *k_flow,
                                      const vr_flow_stats &k_stats,
                                      uint64_t curr_time) {
    FlowEntry *flow = info->flow();
    //If both forward and reverse flow are marked
    //as TCP closed then immediately remote the flow
    if (k_flow != NULL) {
        uint64_t k_flow_bytes, bytes;
        k_flow_bytes = GetFlowStats(k_stats.flow_bytes_oflow,
                                    k_stats.flow_bytes);
        bytes = 0x0000ffffffffffffULL & info->bytes();
        /* Don't account for agent overflow bits while comparing change in
         * stats */
        if (bytes < k_flow_bytes) {
            return false;
        }
    }

    uint64_t diff_time = curr_time - info->last_modified_time();
    if (diff_time < flow_age_time_intvl()) {
        return false;
    }

    if (flow->is_flags_set(FlowEntry::BgpRouterService)) {
        return false;
    }

    return true;
}

uint64_t FlowStatsCollector::GetFlowStats(const uint16_t &oflow_data,
                                          const uint32_t &data) {
    uint64_t flow_stats = (uint64_t) oflow_data << (sizeof(uint32_t) * 8);
    flow_stats |= data;
    return flow_stats;
}

uint64_t FlowStatsCollector::GetUpdatedFlowBytes(const FlowExportInfo *stats,
                                                 uint64_t k_flow_bytes) {
    uint64_t oflow_bytes = 0xffff000000000000ULL & stats->bytes();
    uint64_t old_bytes = 0x0000ffffffffffffULL & stats->bytes();
    if (old_bytes > k_flow_bytes) {
        oflow_bytes += 0x0001000000000000ULL;
    }
    return (oflow_bytes |= k_flow_bytes);
}

uint64_t FlowStatsCollector::GetUpdatedFlowPackets(const FlowExportInfo *stats,
                                                   uint64_t k_flow_pkts) {
    uint64_t oflow_pkts = 0xffffff0000000000ULL & stats->packets();
    uint64_t old_pkts = 0x000000ffffffffffULL & stats->packets();
    if (old_pkts > k_flow_pkts) {
        oflow_pkts += 0x0000010000000000ULL;
    }
    return (oflow_pkts |= k_flow_pkts);
}

void FlowStatsCollector::UpdateFloatingIpStats(const FlowExportInfo *flow,
                                               uint64_t bytes, uint64_t pkts) {
    InterfaceUveTable::FipInfo fip_info;
    FlowEntry *fe = flow->flow();
    if (!fe) {
        return;
    }

    /* Ignore Non-Floating-IP flow */
    if (!fe->fip() || fe->fip_vmi().uuid_ == nil_uuid()) {
        return;
    }

    InterfaceUveStatsTable *table = static_cast<InterfaceUveStatsTable *>
        (agent_uve_->interface_uve_table());

    fip_info.bytes_ = bytes;
    fip_info.packets_ = pkts;
    fip_info.fip_ = fe->fip();
    fip_info.fip_vmi_ = fe->fip_vmi();
    fip_info.is_local_flow_ = fe->is_flags_set(FlowEntry::LocalFlow);
    fip_info.is_ingress_flow_ = fe->is_flags_set(FlowEntry::IngressDir);
    fip_info.is_reverse_flow_ = fe->is_flags_set(FlowEntry::ReverseFlow);
    fip_info.vn_ = fe->data().source_vn_match;

    fip_info.rev_fip_ = NULL;
    if (fe->fip() != ReverseFlowFip(flow)) {
        /* This is the case where Source and Destination VMs (part of
         * same compute node) ping to each other to their respective
         * Floating IPs. In this case for each flow we need to increment
         * stats for both the VMs */
        fip_info.rev_fip_ = ReverseFlowFipEntry(flow);
    }

    table->UpdateFloatingIpStats(fip_info);
}

InterfaceUveTable::FloatingIp *FlowStatsCollector::ReverseFlowFipEntry
    (const FlowExportInfo *flow) {
    uint32_t fip = ReverseFlowFip(flow);
    VmInterfaceKey vmi = ReverseFlowFipVmi(flow);
    Interface *intf = dynamic_cast<Interface *>
        (agent_uve_->agent()->interface_table()->FindActiveEntry(&vmi));

    if (intf) {
        InterfaceUveStatsTable *table = static_cast<InterfaceUveStatsTable *>
            (agent_uve_->interface_uve_table());
        const string &vn = flow->flow()->data().source_vn_match;
        return table->FipEntry(fip, vn, intf);
    }
    return NULL;
}

uint32_t FlowStatsCollector::ReverseFlowFip(const FlowExportInfo *info) {
    FlowEntry *rflow = info->reverse_flow();
    if (rflow) {
        return rflow->fip();
    }
    return 0;
}

VmInterfaceKey FlowStatsCollector::ReverseFlowFipVmi
    (const FlowExportInfo *info)
{
    FlowEntry *rflow = info->reverse_flow();
    if (rflow) {
        return rflow->fip_vmi();
    }
    return VmInterfaceKey(AgentKey::ADD_DEL_CHANGE, nil_uuid(), "");
}

void FlowStatsCollector::UpdateInterVnStats(FlowExportInfo *info,
                                            uint64_t bytes, uint64_t pkts) {
    FlowEntry *flow = info->flow();
    string src_vn = flow->data().source_vn_match;
    string dst_vn = flow->data().dest_vn_match;
    VnUveTable *vn_table = static_cast<VnUveTable *>
        (agent_uve_->vn_uve_table());

    if (!src_vn.length())
        src_vn = FlowHandler::UnknownVn();
    if (!dst_vn.length())
        dst_vn = FlowHandler::UnknownVn();

    /* When packet is going from src_vn to dst_vn it should be interpreted
     * as ingress to vrouter and hence in-stats for src_vn w.r.t. dst_vn
     * should be incremented. Similarly when the packet is egressing vrouter
     * it should be considered as out-stats for dst_vn w.r.t. src_vn.
     * Here the direction "in" and "out" should be interpreted w.r.t vrouter
     */
    if (flow->is_flags_set(FlowEntry::LocalFlow)) {
        vn_table->UpdateInterVnStats(src_vn, dst_vn, bytes, pkts, false);
        vn_table->UpdateInterVnStats(dst_vn, src_vn, bytes, pkts, true);
    } else {
        if (flow->is_flags_set(FlowEntry::IngressDir)) {
            vn_table->UpdateInterVnStats(src_vn, dst_vn, bytes, pkts, false);
        } else {
            vn_table->UpdateInterVnStats(dst_vn, src_vn, bytes, pkts, true);
        }
    }
}

void FlowStatsCollector::UpdateStatsAndExportFlow(FlowExportInfo *info,
                                                  uint64_t teardown_time,
                                                  const RevFlowDepParams *p) {
    if (!info) {
        return;
    }
    FlowEntry *fe = info->flow();
    bool read_flow = true;
    if (info->uuid() != fe->uuid()) {
        /* If UUID for a flow has changed, don't read fields of FlowEntry while
         * sending FlowExport message to collector */
        read_flow = false;
    }
    KSyncFlowMemory *ksync_obj = agent_uve_->agent()->ksync()->
                                         ksync_flow_memory();
    /* Fetch vrouter Flow entry using gen_id and flow_handle from FlowExportInfo
     * to account for the case where FlowEntry's flow_handle/gen_id has changed
     * during Delete processing by FlowStatsCollector */
    vr_flow_stats k_stats;
    const vr_flow_entry *k_flow = ksync_obj->GetKFlowStats(fe->key(),
                                                           info->flow_handle(),
                                                           info->gen_id(),
                                                           &k_stats);
    if (k_flow) {
        UpdateAndExportInternal(info, k_stats.flow_bytes,
                                k_stats.flow_bytes_oflow,
                                k_stats.flow_packets,
                                k_stats.flow_packets_oflow,
                                teardown_time, true, p, read_flow);
        return;
    }
    /* If reading of stats fails, send a message with just teardown time */
    info->set_teardown_time(teardown_time);
    ExportFlow(info, 0, 0, p, read_flow);
}

void FlowStatsCollector::FlowDeleteEnqueue(FlowExportInfo *info, uint64_t t) {
    flows_aged_++;
    FlowEntry *fe = info->flow();
    agent_uve_->agent()->pkt()->get_flow_proto()->DeleteFlowRequest(fe);
    info->set_delete_enqueue_time(t);
    FlowEntry *rflow = info->reverse_flow();
    if (rflow) {
        FlowExportInfo *rev_info = FindFlowExportInfo(rflow);
        if (rev_info) {
            rev_info->set_delete_enqueue_time(t);
        }
    }
}

void FlowStatsCollector::FlowEvictEnqueue(FlowExportInfo *info, uint64_t t,
                                          uint32_t flow_handle,
                                          uint16_t gen_id) {
    flows_evicted_++;
    FlowEntry *fe = info->flow();
    agent_uve_->agent()->pkt()->get_flow_proto()->EvictFlowRequest
        (fe, flow_handle, gen_id, (gen_id + 1));
    info->set_evict_enqueue_time(t);
}

void FlowStatsCollector::UpdateFlowStatsInternal(FlowExportInfo *info,
                                                 uint32_t bytes,
                                                 uint16_t oflow_bytes,
                                                 uint32_t pkts,
                                                 uint16_t oflow_pkts,
                                                 uint64_t time,
                                                 bool teardown_time,
                                                 uint64_t *diff_bytes,
                                                 uint64_t *diff_pkts) {
    uint64_t k_bytes, k_packets, total_bytes, total_packets;
    k_bytes = GetFlowStats(oflow_bytes, bytes);
    k_packets = GetFlowStats(oflow_pkts, pkts);

    total_bytes = GetUpdatedFlowBytes(info, k_bytes);
    total_packets = GetUpdatedFlowPackets(info, k_packets);
    *diff_bytes = total_bytes - info->bytes();
    *diff_pkts = total_packets - info->packets();
    info->set_bytes(total_bytes);
    info->set_packets(total_packets);

    //Update Inter-VN stats
    UpdateInterVnStats(info, *diff_bytes, *diff_pkts);
    //Update Floating-IP stats
    UpdateFloatingIpStats(info, *diff_bytes, *diff_pkts);
    if (teardown_time) {
        info->set_teardown_time(time);
    } else {
        info->set_last_modified_time(time);
    }
}

void FlowStatsCollector::UpdateAndExportInternalLocked(FlowExportInfo *info,
                                                       uint32_t bytes,
                                                       uint16_t oflow_bytes,
                                                       uint32_t pkts,
                                                       uint16_t oflow_pkts,
                                                       uint64_t time,
                                                       bool teardown_time,
                                                   const RevFlowDepParams *p) {
    FlowEntry *flow = info->flow();
    FlowEntry *rflow = info->reverse_flow();
    FLOW_LOCK(flow, rflow, FlowEvent::FLOW_MESSAGE);
    UpdateAndExportInternal(info, bytes, oflow_bytes, pkts, oflow_pkts, time,
                            teardown_time, p, true);
}

void FlowStatsCollector::UpdateAndExportInternal(FlowExportInfo *info,
                                                 uint32_t bytes,
                                                 uint16_t oflow_bytes,
                                                 uint32_t pkts,
                                                 uint16_t oflow_pkts,
                                                 uint64_t time,
                                                 bool teardown_time,
                                                 const RevFlowDepParams *p,
                                                 bool read_flow) {
    uint64_t diff_bytes, diff_pkts;
    UpdateFlowStatsInternal(info, bytes, oflow_bytes, pkts, oflow_pkts, time,
                            teardown_time, &diff_bytes, &diff_pkts);
    ExportFlow(info, diff_bytes, diff_pkts, p, read_flow);
}

// Check if flow needs to be evicted
bool FlowStatsCollector::EvictFlow(KSyncFlowMemory *ksync_obj,
                                   const vr_flow_entry *k_flow,
                                   uint16_t k_flow_flags,
                                   uint32_t flow_handle, uint16_t gen_id,
                                   FlowExportInfo *info, uint64_t curr_time) {
    FlowEntry *fe = info->flow();

    if ((fe->key().protocol != IPPROTO_TCP))
        return false;

    if (ksync_obj->IsEvictionMarked(k_flow, k_flow_flags) == false)
        return false;

    // Flow evict already enqueued? Re-Enqueue request after retry-time
    uint64_t evict_time = info->evict_enqueue_time();
    if (evict_time) {
        if ((curr_time - evict_time) > kFlowDeleteRetryTime) {
            FlowEvictEnqueue(info, curr_time, flow_handle, gen_id);
        }
    } else {
        FlowEvictEnqueue(info, curr_time, flow_handle, gen_id);
    }

    return true;
}

bool FlowStatsCollector::AgeFlow(KSyncFlowMemory *ksync_obj,
                                 const vr_flow_entry *k_flow,
                                 const vr_flow_stats &k_stats,
                                 const KFlowData& kinfo,
                                 FlowExportInfo *info, uint64_t curr_time) {
    FlowEntry *fe = info->flow();
    FlowEntry *rfe = info->reverse_flow();

    // if we come across deleted entry, retry flow deletion after some time
    // duplicate delete will be suppressed in flow_table
    uint64_t delete_time = info->delete_enqueue_time();
    if (delete_time) {
        if ((curr_time - delete_time) > kFlowDeleteRetryTime) {
            FlowDeleteEnqueue(info, curr_time);
        }
        return true;
    }

    // Delete short flows
    if ((flow_stats_manager_->delete_short_flow() == true) &&
        fe->is_flags_set(FlowEntry::ShortFlow)) {
        FlowDeleteEnqueue(info, curr_time);
        return true;
    }

    bool deleted = false;
    FlowExportInfo *rev_info = NULL;
    // Can the flow be aged?
    if (ShouldBeAged(info, k_flow, k_stats, curr_time)) {
        rev_info = FindFlowExportInfo(rfe);
        // ShouldBeAged looks at one flow only. So, check for both forward and
        // reverse flows
        if (rev_info) {
            const vr_flow_entry *k_flow_rev = NULL;
            vr_flow_stats k_rflow_stats;
            k_flow_rev = ksync_obj->GetKFlowStats(rfe->key(),
                                                  rev_info->flow_handle(),
                                                  rev_info->gen_id(),
                                                  &k_rflow_stats);
            if (ShouldBeAged(rev_info, k_flow_rev, k_rflow_stats, curr_time)) {
                deleted = true;
            }
        } else {
            deleted = true;
        }
    }

    if (deleted == true) {
        FlowDeleteEnqueue(info, curr_time);
    }

    // Update stats for flows not being deleted
    // Stats for deleted flow are updated when we get DELETE message
    if (deleted == false && k_flow) {
        uint64_t k_bytes, bytes;

        k_bytes = GetFlowStats(k_stats.flow_bytes_oflow,
                               k_stats.flow_bytes);
        bytes = 0x0000ffffffffffffULL & info->bytes();
        /* Always copy udp source port even though vrouter does not change
         * it. Vrouter many change this behavior and recompute source port
         * whenever flow action changes. To keep agent independent of this,
         * always copy UDP source port */
        info->set_underlay_source_port(kinfo.underlay_src_port);
        info->set_tcp_flags(kinfo.tcp_flags);
        /* Don't account for agent overflow bits while comparing change in
         * stats */
        if (bytes != k_bytes) {
            UpdateAndExportInternalLocked(info,
                                          k_stats.flow_bytes,
                                          k_stats.flow_bytes_oflow,
                                          k_stats.flow_packets,
                                          k_stats.flow_packets_oflow,
                                          curr_time, false, NULL);
        } else if (info->changed()) {
            /* export flow (reverse) for which traffic is not seen yet. */
            ExportFlowLocked(info, 0, 0, NULL);
        }
    }
    return deleted;
}

// Check if a flow is to be aged or evicted. Returns number of flows visited
uint32_t FlowStatsCollector::ProcessFlow(FlowExportInfoList::iterator &it,
                                         KSyncFlowMemory *ksync_obj,
                                         FlowExportInfo *info,
                                         uint64_t curr_time) {
    uint32_t count = 1;
    FlowEntry *fe = info->flow();
    /* Use flow-handle and gen-id from FlowExportInfo instead of FlowEntry.
     * The stats that FlowExportInfo holds corresponds to a given
     * (FlowKey, gen-id and FlowHandle). Since gen-id/flow-handle for a flow
     * can change dynamically, we need to pick gen-id and flow-handle from
     * FlowExportInfo. Otherwise stats will go wrong. Whenever gen-id/
     * flow-handle changes, the stats will be reset as part of AddFlow API
     */
    uint32_t flow_handle = info->flow_handle();
    uint16_t gen_id = info->gen_id();

    /* If Flow handle is still not populated in FlowStatsCollector, pick the
     * value from FlowEntry
     */
    if (flow_handle == FlowEntry::kInvalidFlowHandle) {
        {
            FlowEntry *rflow = NULL;
            FLOW_LOCK(fe, rflow, FlowEvent::FLOW_MESSAGE);
            // since flow processing and stats collector can run in parallel
            // flow handle and gen id not being the key for flow entry can
            // change while processing, so flow handle and gen id should be
            // fetched by holding an lock.
            flow_handle = fe->flow_handle();
            gen_id = fe->gen_id();
            info->CopyFlowInfo(fe);
        }
    }
    const vr_flow_entry *k_flow = NULL;
    vr_flow_stats k_stats;
    KFlowData kinfo;

    /* Teardown time is set when Evicted flow stats update message is received.
     * For flows whose teardown time is set, we need not read stats from
     * vrouter
     */
    if (!info->teardown_time()) {
        k_flow = ksync_obj->GetKFlowStatsAndInfo(fe->key(), flow_handle,
                                                 gen_id, &k_stats, &kinfo);

        // Flow evicted?
        if (EvictFlow(ksync_obj, k_flow, kinfo.flags, flow_handle, gen_id,
                      info, curr_time) == true) {
            // If retry_delete_ enabled, dont change flow_export_info_list_
            if (retry_delete_ == true)
                return count;

            // We dont want to retry delete-events, remove flow from ageing list
            assert(info->is_linked());
            FlowExportInfoList::iterator flow_it =
                flow_export_info_list_.iterator_to(*info);
            flow_export_info_list_.erase(flow_it);

            return count;
        }
    }

    // Flow aged?
    if (AgeFlow(ksync_obj, k_flow, k_stats, kinfo, info, curr_time) == false)
        return count;

    // If retry_delete_ enabled, dont change flow_export_info_list_
    if (retry_delete_ == false)
        return count;

    // Flow aged, remove both forward and reverse flow
    assert(info->is_linked());
    FlowExportInfoList::iterator flow_it =
        flow_export_info_list_.iterator_to(*info);
    flow_export_info_list_.erase(flow_it);

    FlowEntry *rfe = info->reverse_flow();
    FlowExportInfo *rev_info = FindFlowExportInfo(rfe);
    if (rev_info) {
        if (rev_info->is_linked()) {
            FlowExportInfoList::iterator rev_flow_it =
                flow_export_info_list_.iterator_to(*rev_info);
            if (rev_flow_it == it) {
                it++;
            }
            flow_export_info_list_.erase(rev_flow_it);
        }
        count++;
    }
    return count;
}

uint32_t FlowStatsCollector::RunAgeing(uint32_t max_count) {
    FlowExportInfoList::iterator it;
    if (flow_iteration_key_ == NULL) {
        it = flow_export_info_list_.begin();
    } else {
        FlowEntryTree::iterator tree_it = flow_tree_.find(flow_iteration_key_);
        // Flow to iterate next is not found. Force stop this iteration.
        // We will continue from begining on next timer
        if (tree_it == flow_tree_.end()) {
            flow_iteration_key_ = NULL;
            return entries_to_visit_;
        }
        it = flow_export_info_list_.iterator_to(tree_it->second);
    }

    KSyncFlowMemory *ksync_obj = agent_uve_->agent()->ksync()->
        ksync_flow_memory();
    uint64_t curr_time = GetCurrentTime();
    uint32_t count = 0;
    while (count < max_count) {
        if (it == flow_export_info_list_.end()) {
            break;
        }

        FlowExportInfo *info = &(*it);
        it++;
        flows_visited_++;
        count += ProcessFlow(it, ksync_obj, info, curr_time);
    }

    //Send any pending flow export messages
    DispatchPendingFlowMsg();

    // Update iterator for next pass
    if (it == flow_export_info_list_.end()) {
        flow_iteration_key_ = NULL;
    } else {
        flow_iteration_key_ = it->flow();
    }

    return count;
}

// Timer fired for ageing. Update the number of entries to visit and start the
// task if its already not ruuning
bool FlowStatsCollector::Run() {
    if (flow_tree_.size() == 0) {
        return true;
     }

    // Update number of entries to visit in flow.
    UpdateEntriesToVisit();

    // Start task to scan the entries
    if (ageing_task_ == NULL) {
        ageing_task_starts_++;

        if (flow_ageing_debug_) {
            LOG(DEBUG,
                UTCUsecToString(ClockMonotonicUsec())
                << " AgeingTasks Num " << ageing_task_starts_
                << " Request count " << request_queue_.Length()
                << " Tree size " << flow_tree_.size()
                << " List size " << flow_export_info_list_.size()
                << " flows visited " << flows_visited_
                << " flows aged " << flows_aged_
                << " flows evicted " << flows_evicted_);
        }
        flows_visited_ = 0;
        flows_aged_ = 0;
        flows_evicted_ = 0;
        ageing_task_ = new AgeingTask(this);
        agent_uve_->agent()->task_scheduler()->Enqueue(ageing_task_);
    }
    return true;
}

bool FlowStatsCollector::RunAgeingTask() {
    // Run ageing per task
    uint32_t count = RunAgeing(kFlowsPerTask);
    // Update number of entries visited
    if (count < entries_to_visit_)
        entries_to_visit_ -= count;
    else
        entries_to_visit_ = 0;
    // Done with task if we reach end of tree or count is exceeded
    if (flow_iteration_key_ == NULL || entries_to_visit_ == 0) {
        entries_to_visit_ = 0;
        ageing_task_ = NULL;
        return true;
    }

    // More entries to visit. Continue the task
    return false;
}

/////////////////////////////////////////////////////////////////////////////
// Utility methods to enqueue events into work-queue
/////////////////////////////////////////////////////////////////////////////
void FlowStatsCollector::AddEvent(const FlowEntryPtr &flow) {
    FlowExportInfo info(flow, GetCurrentTime());
    boost::shared_ptr<FlowExportReq>
        req(new FlowExportReq(FlowExportReq::ADD_FLOW, info));
    request_queue_.Enqueue(req);
}

void FlowStatsCollector::DeleteEvent(const FlowEntryPtr &flow,
                                     const RevFlowDepParams &params) {
    FlowExportInfo info(flow);
    boost::shared_ptr<FlowExportReq>
        req(new FlowExportReq(FlowExportReq::DELETE_FLOW, info,
                              GetCurrentTime(), params));
    request_queue_.Enqueue(req);
}

void FlowStatsCollector::UpdateStatsEvent(const FlowEntryPtr &flow,
                                          uint32_t bytes,
                                          uint32_t packets,
                                          uint32_t oflow_bytes,
                                          const boost::uuids::uuid &u) {
    FlowExportInfo info(flow);
    boost::shared_ptr<FlowExportReq>
        req(new FlowExportReq(FlowExportReq::UPDATE_FLOW_STATS, info, bytes,
                              packets, oflow_bytes, u));
    request_queue_.Enqueue(req);
}

void FlowStatsCollector::SetUnderlayInfo(FlowExportInfo *info,
                                         FlowLogData &s_flow) {
    string rid = agent_uve_->agent()->router_id().to_string();
    FlowEntry *flow = info->flow();
    uint16_t underlay_src_port = 0;
    if (flow->is_flags_set(FlowEntry::LocalFlow)) {
        s_flow.set_vrouter_ip(rid);
        s_flow.set_other_vrouter_ip(rid);
        /* Set source_port as 0 for local flows. Source port is calculated by
         * vrouter irrespective of whether flow is local or not. So for local
         * flows we need to ignore port given by vrouter
         */
        s_flow.set_underlay_source_port(0);
    } else {
        s_flow.set_vrouter_ip(rid);
        s_flow.set_other_vrouter_ip(flow->peer_vrouter());
        if (flow->tunnel_type().GetType() != TunnelType::MPLS_GRE) {
            underlay_src_port = info->underlay_source_port();
        }
        s_flow.set_underlay_source_port(underlay_src_port);
    }
    s_flow.set_underlay_proto(flow->tunnel_type().GetType());
}

/* For ingress flows, change the SIP as Nat-IP instead of Native IP */
void FlowStatsCollector::SourceIpOverride(FlowExportInfo *info,
                                          FlowLogData &s_flow,
                                          const RevFlowDepParams *params) {
    if (params && params->sip_.is_v4()) {
        s_flow.set_sourceip(params->sip_);
        return;
    }
    FlowEntry *flow = info->flow();
    FlowEntry *rflow = info->reverse_flow();
    if (flow->is_flags_set(FlowEntry::NatFlow) && s_flow.get_direction_ing() &&
        rflow) {
        const FlowKey *nat_key = &rflow->key();
        if (flow->key().src_addr != nat_key->dst_addr) {
            s_flow.set_sourceip(nat_key->dst_addr);
        }
    }
}

void FlowStatsCollector::SetImplicitFlowDetails(FlowExportInfo *info,
                                                FlowLogData &s_flow,
                                                const RevFlowDepParams *params) {

    FlowEntry *rflow = info->reverse_flow();

    if (rflow) {
        s_flow.set_flowuuid(to_string(rflow->egress_uuid()));
        s_flow.set_vm(rflow->data().vm_cfg_name);
        s_flow.set_sg_rule_uuid(rflow->sg_rule_uuid());
        if (rflow->intf_entry()) {
            s_flow.set_vmi_uuid(UuidToString(rflow->intf_entry()->GetUuid()));
        }
        s_flow.set_reverse_uuid(to_string(rflow->uuid()));
    } else if (params) {
        s_flow.set_flowuuid(to_string(params->rev_egress_uuid_));
        s_flow.set_vm(params->vm_cfg_name_);
        s_flow.set_sg_rule_uuid(params->sg_uuid_);
        s_flow.set_reverse_uuid(to_string(params->rev_uuid_));
        s_flow.set_vmi_uuid(params->vmi_uuid_);
    }
}

void FlowStatsCollector::GetFlowSandeshActionParams
    (const FlowAction &action_info, std::string &action_str) {
    std::bitset<32> bs(action_info.action);
    for (unsigned int i = 0; i <= bs.size(); i++) {
        if (bs[i]) {
            if (!action_str.empty()) {
                action_str += "|";
            }
            action_str += TrafficAction::ActionToString(
                static_cast<TrafficAction::Action>(i));
        }
    }
}

void FlowStatsCollector::EnqueueFlowMsg() {
    msg_index_++;
    if (msg_index_ == kMaxFlowMsgsPerSend) {
        DispatchFlowMsg(msg_list_);
        msg_index_ = 0;
    }
}

void FlowStatsCollector::DispatchPendingFlowMsg() {
    if (msg_index_ == 0) {
        return;
    }

    vector<FlowLogData>::const_iterator first = msg_list_.begin();
    vector<FlowLogData>::const_iterator last = msg_list_.begin() + msg_index_;
    vector<FlowLogData> new_list(first, last);
    DispatchFlowMsg(new_list);
    msg_index_ = 0;
}

void FlowStatsCollector::DispatchFlowMsg(const std::vector<FlowLogData> &lst) {
    FLOW_LOG_DATA_OBJECT_LOG("", SandeshLevel::SYS_INFO, lst);
}

uint8_t FlowStatsCollector::GetFlowMsgIdx() {
    FlowLogData &obj = msg_list_[msg_index_];
    obj = FlowLogData();
    return msg_index_;
}

void FlowStatsCollector::ExportFlowLocked(FlowExportInfo *info,
                                          uint64_t diff_bytes,
                                          uint64_t diff_pkts,
                                          const RevFlowDepParams *params) {
    FlowEntry *flow = info->flow();
    FlowEntry *rflow = info->reverse_flow();
    FLOW_LOCK(flow, rflow, FlowEvent::FLOW_MESSAGE);
    ExportFlow(info, diff_bytes, diff_pkts, params, true);
}

/* Flow Export Algorithm
 * (1) Flow samples greater than or equal to sampling threshold will always be
 * exported, with the byte/packet counts reported as-is.
 * (2) Flow samples smaller than the sampling threshold will be exported
 * probabilistically, with the byte/packets counts adjusted upwards according to
 * the probability.
 * (3) Probability =  diff_bytes/sampling_threshold
 * (4) We generate a random number less than sampling threshold.
 * (5) If the diff_bytes is greater than random number then the flow is dropped
 * (6) Otherwise the flow is exported after normalizing the diff bytes and
 * packets. The normalization is done by dividing diff_bytes and diff_pkts with
 * probability. This normalization is used as heuristictic to account for stats
 * of dropped flows */
void FlowStatsCollector::ExportFlow(FlowExportInfo *info,
                                    uint64_t diff_bytes,
                                    uint64_t diff_pkts,
                                    const RevFlowDepParams *params,
                                    bool read_flow) {
    assert((agent_uve_->agent()->tsn_enabled() == false));
    FlowEntry *flow = info->flow();
    FlowEntry *rflow = info->reverse_flow();

    /* Drop Deleted Flow export messages if add for it was never exported. This
     * includes only those delete messages where we cannot read FlowEntry
     * because deleted msg is for a Flow UUID which is different from the UUID
     * in FlowEntry pointer
     */
    if (!info->exported_atleast_once() && !read_flow) {
        assert(info->teardown_time());
        flow_stats_manager_->deleted_flow_export_drops_++;
        return;
    }

    int32_t cfg_rate = agent_uve_->agent()->oper_db()->global_vrouter()->
                        flow_export_rate();
    /* We should always try to export flows with Action as LOG regardless of
     * configured flow-export-rate */
    if (!info->IsActionLog() && !cfg_rate) {
        flow_stats_manager_->flow_export_disable_drops_++;
        return;
    }

    /* Subject a flow to sampling algorithm only when all of below is met:-
     * a. if Log is not configured as action for flow
     * b. actual flow-export-rate is >= 80% of configured flow-export-rate. This
     *    is done only for first time.
     * c. diff_bytes is lesser than the threshold
     * d. Flow-sampling is not disabled
     * e. Flow-sample does not have teardown time or the sample for the flow is
     *    not exported earlier.
     */
    bool subject_flows_to_algorithm = false;
    if (!info->IsActionLog() && (diff_bytes < threshold()) &&
        (cfg_rate != GlobalVrouter::kDisableSampling) &&
        (!info->teardown_time() || !info->exported_atleast_once()) &&
        ((!flow_stats_manager_->flows_sampled_atleast_once_ &&
         flow_stats_manager_->flow_export_rate() >= ((double)cfg_rate) * 0.8)
         || flow_stats_manager_->flows_sampled_atleast_once_)) {
        subject_flows_to_algorithm = true;
        flow_stats_manager_->set_flows_sampled_atleast_once();
    }

    if (subject_flows_to_algorithm) {
        double probability = diff_bytes/threshold();
        uint32_t num = rand() % threshold();
        if (num > diff_bytes) {
            /* Do not export the flow, if the random number generated is more
             * than the diff_bytes */
            flow_stats_manager_->flow_export_sampling_drops_++;
            /* The second part of the if condition below is not required but
             * added for better readability. It is not required because
             * exported_atleast_once() will always be false if teardown time is
             * set. If both teardown_time and exported_atleast_once are true we
             * will never be here */
            if (info->teardown_time() && !info->exported_atleast_once()) {
                flow_stats_manager_->flow_export_drops_++;
            }
            return;
        }
        /* Normalize the diff_bytes and diff_packets reported using the
         * probability value */
        if (probability == 0) {
            diff_bytes = diff_pkts = 0;
        } else {
            diff_bytes = diff_bytes/probability;
            diff_pkts = diff_pkts/probability;
        }
    }
    /* Mark the flow as exported */
    info->set_exported_atleast_once(true);

    FlowLogData &s_flow = msg_list_[GetFlowMsgIdx()];

    s_flow.set_flowuuid(to_string(flow->uuid()));
    s_flow.set_bytes(info->bytes());
    s_flow.set_packets(info->packets());
    s_flow.set_diff_bytes(diff_bytes);
    s_flow.set_diff_packets(diff_pkts);
    s_flow.set_setup_time(info->setup_time());
    if (info->teardown_time()) {
        s_flow.set_teardown_time(info->teardown_time());
    }
    info->set_changed(false);

    if (read_flow) {
        s_flow.set_tcp_flags(info->tcp_flags());
        s_flow.set_sourceip(flow->key().src_addr);
        s_flow.set_destip(flow->key().dst_addr);
        s_flow.set_protocol(flow->key().protocol);
        s_flow.set_sport(flow->key().src_port);
        s_flow.set_dport(flow->key().dst_port);
        s_flow.set_sourcevn(flow->data().source_vn_match);
        s_flow.set_destvn(flow->data().dest_vn_match);
        s_flow.set_vm(flow->data().vm_cfg_name);
        if (info->is_flags_set(FlowEntry::ReverseFlow)) {
            s_flow.set_forward_flow(false);
        } else {
            s_flow.set_forward_flow(true);
        }

        string drop_reason = FlowEntry::DropReasonStr(flow->data().drop_reason);
        s_flow.set_drop_reason(drop_reason);

        s_flow.set_sg_rule_uuid(flow->sg_rule_uuid());
        s_flow.set_nw_ace_uuid(flow->nw_ace_uuid());
        if (flow->intf_entry()) {
            s_flow.set_vmi_uuid(UuidToString(flow->intf_entry()->GetUuid()));
        }

        if (rflow) {
            s_flow.set_reverse_uuid(to_string(rflow->uuid()));
        } else if (params) {
            s_flow.set_reverse_uuid(to_string(params->rev_uuid_));
        }

        // Set flow action
        std::string action_str;
        GetFlowSandeshActionParams(flow->data().match_p.action_info, action_str);
        s_flow.set_action(action_str);
        SetUnderlayInfo(info, s_flow);
    }

    if (info->is_flags_set(FlowEntry::LocalFlow)) {
        /* For local flows we need to send two flow log messages.
         * 1. With direction as ingress
         * 2. With direction as egress
         * For local flows we have already sent flow log above with
         * direction as ingress. We are sending flow log below with
         * direction as egress.
         */
        s_flow.set_direction_ing(1);
        if (read_flow) {
            s_flow.set_reverse_uuid(to_string(flow->egress_uuid()));
            SourceIpOverride(info, s_flow, params);
        }
        EnqueueFlowMsg();

        FlowLogData &s_flow2 = msg_list_[GetFlowMsgIdx()];
        s_flow2 = s_flow;
        s_flow2.set_direction_ing(0);
        //Update the interface and VM name in this flow
        //For the reverse flow this would be egress flow
        //For example
        //    VM1 A --> B is fwd flow
        //    VM2 B --> A is rev flow
        //
        //Egress flow for fwd flow would be exported
        //while exporting rev flow, this done so that
        //key, stats and other stuff can be copied over
        //from current flow
        if (read_flow) {
            SetImplicitFlowDetails(info, s_flow2, params);
        } else {
            s_flow2.set_flowuuid(to_string(info->rev_flow_egress_uuid()));
        }
        //Export local flow of egress direction with a different UUID even when
        //the flow is same. Required for analytics module to query flows
        //irrespective of direction.
        EnqueueFlowMsg();
        flow_stats_manager_->UpdateFlowExportStats(2,
                                                   subject_flows_to_algorithm);
    } else {
        if (info->is_flags_set(FlowEntry::IngressDir)) {
            s_flow.set_direction_ing(1);
            if (read_flow) {
                SourceIpOverride(info, s_flow, params);
            }
        } else {
            s_flow.set_direction_ing(0);
        }
        EnqueueFlowMsg();
        flow_stats_manager_->UpdateFlowExportStats(1,
                                                   subject_flows_to_algorithm);
    }
}

bool FlowStatsManager::UpdateFlowThreshold() {
    uint64_t curr_time = FlowStatsCollector::GetCurrentTime();
    bool export_rate_calculated = false;
    uint32_t exp_rate_without_sampling = 0;

    /* If flows are not being exported, no need to update threshold */
    if (!flow_export_count_) {
        return true;
    }

    // Calculate Flow Export rate
    if (prev_flow_export_rate_compute_time_) {
        uint64_t diff_secs = 0;
        uint64_t diff_micro_secs = curr_time -
            prev_flow_export_rate_compute_time_;
        if (diff_micro_secs) {
            diff_secs = diff_micro_secs/1000000;
        }
        if (diff_secs) {
            uint32_t flow_export_count = flow_export_count_reset();
            flow_export_rate_ = flow_export_count/diff_secs;
            exp_rate_without_sampling =
                flow_export_without_sampling_reset()/diff_secs;
            prev_flow_export_rate_compute_time_ = curr_time;
            export_rate_calculated = true;
        }
    } else {
        prev_flow_export_rate_compute_time_ = curr_time;
        flow_export_count_ = 0;
        return true;
    }

    uint32_t cfg_rate = agent_->oper_db()->global_vrouter()->
                            flow_export_rate();
    /* No need to update threshold when flow_export_rate is NOT calculated
     * and configured flow export rate has not changed */
    if (!export_rate_calculated &&
        (cfg_rate == prev_cfg_flow_export_rate_)) {
        return true;
    }
    uint64_t cur_t = threshold(), new_t = 0;
    // Update sampling threshold based on flow_export_rate_
    if (flow_export_rate_ < ((double)cfg_rate) * 0.8) {
        /* There are two reasons why we can be here.
         * 1. None of the flows were sampled because we never crossed
         *    80% of configured flow-export-rate.
         * 2. In scale setups, the threshold was updated to high value because
         *    of which flow-export-rate has dropped drastically.
         * Threshold should be updated here depending on which of the above two
         * situations we are in. */
        if (!flows_sampled_atleast_once_) {
            UpdateThreshold(kDefaultFlowSamplingThreshold, false);
        } else {
            if (flow_export_rate_ < ((double)cfg_rate) * 0.5) {
                UpdateThreshold((threshold_ / 4), false);
            } else {
                UpdateThreshold((threshold_ / 2), false);
            }
        }
    } else if (flow_export_rate_ > (cfg_rate * 3)) {
        UpdateThreshold((threshold_ * 4), true);
    } else if (flow_export_rate_ > (cfg_rate * 2)) {
        UpdateThreshold((threshold_ * 3), true);
    } else if (flow_export_rate_ > ((double)cfg_rate) * 1.25) {
        UpdateThreshold((threshold_ * 2), true);
    }
    prev_cfg_flow_export_rate_ = cfg_rate;
    new_t = threshold();
    FLOW_EXPORT_STATS_TRACE(flow_export_rate_, exp_rate_without_sampling, cur_t,
                            new_t);
    return true;
}

uint64_t FlowStatsCollector::threshold() const {
    return flow_stats_manager_->threshold();
}

uint32_t FlowStatsCollector::flow_export_count() const {
    return flow_stats_manager_->flow_export_count();
}

bool FlowStatsCollector::RequestHandlerEntry() {
    current_time_ = GetCurrentTime();
    return true;
}

/*
 * The DELETE_FLOW processing would have enqueued FlowLog messages. However,
 * if we have not hit max messages to be sent, it will not dispatch. Invoke
 * DispatchPendingFlowMsg to send pending messages from
 * FlowStatsCollector::RequestHandler
 */
void FlowStatsCollector::RequestHandlerExit(bool done) {
    DispatchPendingFlowMsg();
}

bool FlowStatsCollector::RequestHandler(boost::shared_ptr<FlowExportReq> req) {
    const FlowExportInfo &info = req->info();
    FlowEntry *flow = info.flow();
    FlowEntry *rflow = info.reverse_flow();
    FLOW_LOCK(flow, rflow, FlowEvent::FLOW_MESSAGE);

    switch (req->event()) {
    case FlowExportReq::ADD_FLOW: {
        AddFlow(req->info());
        break;
    }

    case FlowExportReq::DELETE_FLOW: {
        FlowEntryTree::iterator it;
        // Get the FlowExportInfo for flow
        if (FindFlowExportInfo(flow, it) == false)
            break;

        /* We don't export flows in TSN mode */
        if (agent_uve_->agent()->tsn_enabled() == false) {
            FlowExportInfo *info = &it->second;
            /* While updating stats for evicted flows, we set the teardown_time
             * and export the flow. So delete handling for evicted flows need
             * not update stats and export flow */
            if (!info->teardown_time()) {
                UpdateStatsAndExportFlow(info, req->time(), &req->params());
            }
        }
        /* Remove the entry from our tree */
        DeleteFlow(it);
        break;
    }

    case FlowExportReq::UPDATE_FLOW_STATS: {
        EvictedFlowStatsUpdate(flow, req->bytes(), req->packets(),
                               req->oflow_bytes(), req->uuid());
        break;
    }

    default:
         assert(0);
    }

    if (deleted_ && parent_->CanDelete()) {
        flow_stats_manager_->Free(flow_aging_key_);
    }

    return true;
}

FlowExportInfo *
FlowStatsCollector::FindFlowExportInfo(const FlowEntry *fe) {
    FlowEntryTree::iterator it = flow_tree_.find(fe);
    if (it == flow_tree_.end()) {
        return NULL;
    }

    return &it->second;
}

const FlowExportInfo *
FlowStatsCollector::FindFlowExportInfo(const FlowEntry *fe) const {
    FlowEntryTree::const_iterator it = flow_tree_.find(fe);
    if (it == flow_tree_.end()) {
        return NULL;
    }

    return &it->second;
}

bool FlowStatsCollector::FindFlowExportInfo(const FlowEntry *fe,
                                            FlowEntryTree::iterator &it) {
    it = flow_tree_.find(fe);
    if (it == flow_tree_.end()) {
        return false;
    }
    return true;
}

void FlowStatsCollector::NewFlow(FlowEntry *flow) {
    const FlowKey &key = flow->key();
    uint8_t proto = key.protocol;
    uint16_t sport = key.src_port;
    uint16_t dport = key.dst_port;

    // Update vrouter port bitmap
    VrouterUveEntry *vre = static_cast<VrouterUveEntry *>(
        agent_uve_->vrouter_uve_entry());
    vre->UpdateBitmap(proto, sport, dport);

    // Update source-vn port bitmap
    VnUveTable *vnte = static_cast<VnUveTable *>(agent_uve_->vn_uve_table());
    vnte->UpdateBitmap(flow->data().source_vn_match, proto, sport, dport);
    // Update dest-vn port bitmap
    vnte->UpdateBitmap(flow->data().dest_vn_match, proto, sport, dport);

    const VmInterface *port = dynamic_cast<const VmInterface *>
        (flow->intf_entry());
    if (port == NULL) {
        return;
    }
    const VmEntry *vm = port->vm();
    if (vm == NULL) {
        return;
    }

    // update vm and interface (all interfaces of vm) bitmap
    VmUveTable *vmt = static_cast<VmUveTable *>(agent_uve_->vm_uve_table());
    vmt->UpdateBitmap(vm, proto, sport, dport);
}

void FlowStatsCollector::AddFlow(FlowExportInfo info) {
    /* Before inserting update the gen_id and flow_handle in FlowExportInfo.
     * Locks for accessing fields of flow are taken in calling function.
     */
    FlowEntry* fe = info.flow();
    info.CopyFlowInfo(fe);
    std::pair<FlowEntryTree::iterator, bool> ret =
        flow_tree_.insert(make_pair(fe, info));
    if (ret.second == false) {
        FlowExportInfo &prev = ret.first->second;
        if (prev.uuid() != fe->uuid()) {
            /* Received ADD request for already added entry with a different
             * UUID. Because of state-compression of messages to
             * FlowStatsCollector in FlowMgmt, we have not received DELETE for
             * previous UUID. Send FlowExport to indicate delete for the flow.
             * This export need not be sent if teardown time is already set.
             * Teardown time would be set if EvictedFlowStats update request
             * comes before this duplicate add.
             */
            if (!prev.teardown_time()) {
                UpdateStatsAndExportFlow(&prev, info.setup_time(), NULL);
            }
            /* After sending Delete to collector (if required), reset the stats
             */
            prev.ResetStats();
        }
        prev.CopyFlowInfo(fe);
        prev.set_changed(true);
        prev.set_delete_enqueue_time(0);
        prev.set_evict_enqueue_time(0);
        prev.set_teardown_time(0);
    } else {
        NewFlow(info.flow());
    }
    if (ret.first->second.is_linked() == false) {
        flow_export_info_list_.push_back(ret.first->second);
    }
}

// The flow being deleted may be the first flow to visit in next ageing
// iteration. Update the flow to visit next in such case
void FlowStatsCollector::UpdateFlowIterationKey
(const FlowEntry *del_flow, FlowEntryTree::iterator &tree_it) {
    // Flow not found in tree is not a valid scenario. Lets be safe and
    // restart walk here
    if (tree_it == flow_tree_.end()) {
        flow_iteration_key_ = NULL;
    }

    if (flow_iteration_key_ == NULL) {
        return;
    }

    // The flow to visit next for ageing is being deleted. Update next flow to
    // visit
    FlowExportInfoList::iterator it =
        flow_export_info_list_.iterator_to(tree_it->second);
    ++it;

    // If this is end of list, start from begining again
    if (it == flow_export_info_list_.end())
        it = flow_export_info_list_.begin();

    if (it == flow_export_info_list_.end()) {
        flow_iteration_key_ = NULL;
    } else {
        flow_iteration_key_ = it->flow();
    }
}

void FlowStatsCollector::DeleteFlow(FlowEntryTree::iterator &it) {
    // Update flow_iteration_key_ if flow being deleted is flow to visit in
    // next ageing cycle
    // Nothing to do if flow being deleted is not the next-iteration key
    if (it->first == flow_iteration_key_) {
        UpdateFlowIterationKey(it->first, it);
    }

    if (it == flow_tree_.end())
        return;

    if (it->second.is_linked()) {
        FlowExportInfoList::iterator it1 =
            flow_export_info_list_.iterator_to(it->second);
        flow_export_info_list_.erase(it1);
    }

    flow_tree_.erase(it);
}

void FlowStatsCollector::EvictedFlowStatsUpdate(const FlowEntryPtr &flow,
                                                uint32_t bytes,
                                                uint32_t packets,
                                                uint32_t oflow_bytes,
                                                const boost::uuids::uuid &u) {
    FlowExportInfo *info = FindFlowExportInfo(flow.get());
    if (info) {
        /* Ignore stats update request for Evicted flow, if we don't have
         * FlowEntry corresponding to the Evicted Flow. The match is done using
         * UUID
         */
        if (info->uuid() != u) {
            return;
        }
        /* We are updating stats of evicted flow. Set teardown_time here.
         * When delete event is being handled we don't export flow if
         * teardown time is set */
        UpdateAndExportInternal(info, bytes, oflow_bytes & 0xFFFF,
                                packets, oflow_bytes & 0xFFFF0000,
                                GetCurrentTime(), true, NULL, false);
    }
}

/////////////////////////////////////////////////////////////////////////////
// Introspect routines
/////////////////////////////////////////////////////////////////////////////
void FlowStatsCollectionParamsReq::HandleRequest() const {
    FlowStatsManager *mgr = Agent::GetInstance()->flow_stats_manager();
    FlowStatsCollectionParamsResp *resp = new FlowStatsCollectionParamsResp();
    resp->set_flow_export_rate(mgr->flow_export_rate());
    resp->set_sampling_threshold(mgr->threshold());

    resp->set_context(context());
    resp->Response();
    return;
}

static void KeyToSandeshFlowKey(const FlowKey &key,
                                SandeshFlowKey &skey) {
    skey.set_nh(key.nh);
    skey.set_sip(key.src_addr.to_string());
    skey.set_dip(key.dst_addr.to_string());
    skey.set_src_port(key.src_port);
    skey.set_dst_port(key.dst_port);
    skey.set_protocol(key.protocol);
}

static void FlowExportInfoToSandesh(const FlowExportInfo &value,
                                    SandeshFlowExportInfo &info) {
    SandeshFlowKey skey;
    FlowEntry *flow = value.flow();
    FlowEntry *rflow = value.reverse_flow();
    KeyToSandeshFlowKey(flow->key(), skey);
    info.set_key(skey);
    info.set_uuid(to_string(flow->uuid()));
    if (rflow) {
        info.set_rev_flow_uuid(to_string(rflow->uuid()));
    }
    info.set_egress_uuid(to_string(value.egress_uuid()));
    info.set_source_vn(flow->data().source_vn_match);
    info.set_dest_vn(flow->data().dest_vn_match);
    info.set_sg_rule_uuid(flow->sg_rule_uuid());
    info.set_nw_ace_uuid(flow->nw_ace_uuid());
    info.set_setup_time(value.setup_time());
    info.set_teardown_time(value.teardown_time());
    info.set_last_modified_time(value.last_modified_time());
    info.set_bytes(value.bytes());
    info.set_packets(value.packets());
    info.set_flags(flow->flags());
    info.set_flow_handle(flow->flow_handle());
    std::vector<ActionStr> action_str_l;
    SetActionStr(flow->data().match_p.action_info, action_str_l);
    info.set_action(action_str_l);
    info.set_vm_cfg_name(flow->data().vm_cfg_name);
    info.set_peer_vrouter(flow->peer_vrouter());
    info.set_tunnel_type(flow->tunnel_type().ToString());
    const VmInterfaceKey &vmi = flow->fip_vmi();
    string vmi_str = to_string(vmi.uuid_) + vmi.name_;
    info.set_fip_vmi(vmi_str);
    Ip4Address ip(flow->fip());
    info.set_fip(ip.to_string());
    info.set_underlay_source_port(value.underlay_source_port());
    info.set_delete_enqueued(value.delete_enqueue_time() ? true : false);
}

void FlowStatsRecordsReq::HandleRequest() const {
    FlowStatsCollector::FlowEntryTree::iterator it;
    vector<FlowStatsRecord> list;
    FlowStatsRecordsResp *resp = new FlowStatsRecordsResp();
    for (int i = 0; i < FlowStatsCollectorObject::kMaxCollectors; i++) {
        FlowStatsCollector *col = Agent::GetInstance()->
            flow_stats_manager()->default_flow_stats_collector_obj()->
            GetCollector(i);
        it = col->flow_tree_.begin();
        while (it != col->flow_tree_.end()) {
            const FlowExportInfo &value = it->second;
            ++it;

            SandeshFlowKey skey;
            KeyToSandeshFlowKey(value.flow()->key(), skey);

            SandeshFlowExportInfo info;
            FlowExportInfoToSandesh(value, info);

            FlowStatsRecord rec;
            rec.set_info(info);
            list.push_back(rec);
        }
    }
    resp->set_records_list(list);

    resp->set_context(context());
    resp->Response();
    return;
}

/////////////////////////////////////////////////////////////////////////////
// Flow Stats Ageing task
/////////////////////////////////////////////////////////////////////////////
FlowStatsCollector::AgeingTask::AgeingTask(FlowStatsCollector *fsc) :
    Task(fsc->task_id(), fsc->instance_id()), fsc_(fsc) {
}

FlowStatsCollector::AgeingTask::~AgeingTask() {
}

std::string FlowStatsCollector::AgeingTask::Description() const {
    return "Flow Stats Collector Ageing Task";
}

bool FlowStatsCollector::AgeingTask::Run() {
    return fsc_->RunAgeingTask();
}

/////////////////////////////////////////////////////////////////////////////
// FlowStatsCollectorObject methods
/////////////////////////////////////////////////////////////////////////////
FlowStatsCollectorObject::FlowStatsCollectorObject(Agent *agent,
                                                   FlowStatsCollectorReq *req,
                                                   FlowStatsManager *mgr) {
    FlowAgingTableKey *key = &(req->key);
    for (int i = 0; i < kMaxCollectors; i++) {
        uint32_t instance_id = mgr->AllocateIndex();
        collectors[i].reset(
            AgentObjectFactory::Create<FlowStatsCollector>(
                *(agent->event_manager()->io_service()),
                req->flow_stats_interval, req->flow_cache_timeout,
                agent->uve(), instance_id, key, mgr, this));
    }
}

FlowStatsCollector* FlowStatsCollectorObject::GetCollector(uint8_t idx) const {
    if (idx >= 0 && idx < kMaxCollectors) {
        return collectors[idx].get();
    }
    return NULL;
}

void FlowStatsCollectorObject::SetExpiryTime(int time) {
    for (int i = 0; i < kMaxCollectors; i++) {
        collectors[i]->set_expiry_time(time);
    }
}

int FlowStatsCollectorObject::GetExpiryTime() const {
    /* Same expiry time would be configured for all the collectors. Pick value
     * from any one of them */
    return collectors[0]->expiry_time();
}

void FlowStatsCollectorObject::MarkDelete() {
    for (int i = 0; i < kMaxCollectors; i++) {
        collectors[i]->set_deleted(true);
    }
}

void FlowStatsCollectorObject::ClearDelete() {
    for (int i = 0; i < kMaxCollectors; i++) {
        collectors[i]->set_deleted(false);
    }
}

bool FlowStatsCollectorObject::IsDeleted() const {
    for (int i = 0; i < kMaxCollectors; i++) {
        if (!collectors[i]->deleted()) {
            return false;
        }
    }
    return true;
}

void FlowStatsCollectorObject::SetFlowAgeTime(uint64_t value) {
    for (int i = 0; i < kMaxCollectors; i++) {
        collectors[i]->set_flow_age_time_intvl(value);
    }
}

uint64_t FlowStatsCollectorObject::GetFlowAgeTime() const {
    /* Same age time would be configured for all the collectors. Pick value
     * from any one of them */
    return collectors[0]->flow_age_time_intvl();
}

bool FlowStatsCollectorObject::CanDelete() const {
    for (int i = 0; i < kMaxCollectors; i++) {
        if (collectors[i]->flow_tree_.size() != 0 ||
            collectors[i]->request_queue_.IsQueueEmpty() == false) {
            return false;
        }
    }
    return true;
}

void FlowStatsCollectorObject::Shutdown() {
    for (int i = 0; i < kMaxCollectors; i++) {
        collectors[i]->Shutdown();
        collectors[i].reset();
    }
}

FlowStatsCollector* FlowStatsCollectorObject::FlowToCollector
    (const FlowEntry *flow) {
    uint8_t idx = 0;
    FlowTable *table = flow->flow_table();
    if (table) {
        idx = table->table_index() % kMaxCollectors;
    }
    return collectors[idx].get();
}

void FlowStatsCollectorObject::UpdateAgeTimeInSeconds(uint32_t age_time) {
    for (int i = 0; i < kMaxCollectors; i++) {
        collectors[i]->UpdateFlowAgeTimeInSecs(age_time);
    }
}

uint32_t FlowStatsCollectorObject::GetAgeTimeInSeconds() const {
    /* Same age time would be configured for all the collectors. Pick value
     * from any one of them */
    return collectors[0]->flow_age_time_intvl_in_secs();
}

size_t FlowStatsCollectorObject::Size() const {
    size_t size = 0;
    for (int i = 0; i < kMaxCollectors; i++) {
        size += collectors[i]->Size();
    }
    return size;
}

max_stars_repo_name: sagarc-contrail/contrail-controller

max_issues_repo_name: sagarc-contrail/contrail-controller

max_forks_repo_name: sagarc-contrail/contrail-controller


text:
#pragma once

#include <ysu/boost/private/macro_warnings.hpp>

DISABLE_BEAST_WARNINGS
#include <boost/beast/version.hpp>
REENABLE_WARNINGS

ext: hpp


text:
#include <opencv2/core/core.hpp>

#include <stdint.h>

#include <string>
#include <vector>

#include "caffe/common.hpp"
#include "caffe/layers/tsv_cpm_data_layer.hpp"
#include "caffe/util/benchmark.hpp"
#include "caffe/util/io.hpp"
#include "caffe/util/rng.hpp"
#include "caffe/util/random_helper.h"

#define BOOST_SPIRIT_THREADSAFE
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>

using boost::property_tree::ptree;
using boost::property_tree::read_json;

namespace caffe {

	template <typename Dtype>
	TsvCPMDataLayer<Dtype>::TsvCPMDataLayer(const LayerParameter& param)
		: TsvDataLayer<Dtype>(param),
		cpm_transform_param_(param.cpm_transform_param()) {
	}

	template <typename Dtype>
	void TsvCPMDataLayer<Dtype>::DataLayerSetUp(const vector<Blob<Dtype>*>& bottom,
		const vector<Blob<Dtype>*>& top) {

		cpm_data_transformer_.reset(
			new CPMDataTransformer<Dtype>(cpm_transform_param_, this->phase_));
		cpm_data_transformer_->InitRand();

		// specify the shape of top[0] & top[1]
		TsvDataLayer<Dtype>::DataLayerSetUp(bottom, top);

		// reshape label
		vector<int> shape = top[1]->shape();
		const int stride = this->layer_param_.cpm_transform_param().stride();
		const int height = this->layer_param_.cpm_transform_param().crop_size_y();
		const int width = this->layer_param_.cpm_transform_param().crop_size_x();

		const int num_parts = this->layer_param_.cpm_transform_param().num_parts();
		top[1]->Reshape(shape[0], 2 * (num_parts + 1), height / stride, width / stride);
		for (int i = 0; i < this->prefetch_.size(); ++i) {
			this->prefetch_[i]->label_.Reshape(shape[0], 2 * (num_parts + 1), height / stride, width / stride);
		}
	}

	template <typename Dtype>
	void TsvCPMDataLayer<Dtype>::process_one_image_and_label(const string &input_b64coded_data, const string &input_label_data, const TsvDataParameter &tsv_param, Dtype *output_image_data, Dtype *output_label_data)
	{
		this->cpm_data_transformer_->Transform_nv2(input_b64coded_data, input_label_data,
			output_image_data, output_label_data, tsv_param.data_format() == TsvDataParameter_DataFormat_ImagePath);
	}

	INSTANTIATE_CLASS(TsvCPMDataLayer);
	REGISTER_LAYER_CLASS(TsvCPMData);

}  // namespace caffe

ext: cpp

max_stars_repo_name: MSRCCS/Caffe

max_issues_repo_name: MSRCCS/Caffe

max_forks_repo_name: MSRCCS/Caffe


text:
// Copyright (c) 2012-2017, The CryptoNote developers, The Bytecoin developers
// Copyright (c) 2018-2019, The TurtleCoin Developers
// Copyright (c) 2020, The Proximus Project
// Please see the included LICENSE file for more information.

#include "BlockchainReadBatch.h"

#include "DBUtils.h"

#include <boost/range/combine.hpp>
#include <config/Constants.h>

using namespace CryptoNote;

BlockchainReadBatch::BlockchainReadBatch() {}

BlockchainReadBatch::~BlockchainReadBatch() {}

BlockchainReadBatch &BlockchainReadBatch::requestSpentKeyImagesByBlock(uint32_t blockIndex)
{
    state.spentKeyImagesByBlock.emplace(blockIndex, std::vector<Crypto::KeyImage>());
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestBlockIndexBySpentKeyImage(const Crypto::KeyImage &keyImage)
{
    state.blockIndexesBySpentKeyImages.emplace(keyImage, 0);
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestCachedTransaction(const Crypto::Hash &txHash)
{
    state.cachedTransactions.emplace(txHash, ExtendedTransactionInfo());
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestCachedTransactions(const std::vector<Crypto::Hash> &transactions)
{
    for (const auto hash : transactions)
    {
        state.cachedTransactions.emplace(hash, ExtendedTransactionInfo());
    }

    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestTransactionHashesByBlock(uint32_t blockIndex)
{
    state.transactionHashesByBlocks.emplace(blockIndex, std::vector<Crypto::Hash>());
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestCachedBlock(uint32_t blockIndex)
{
    state.cachedBlocks.emplace(blockIndex, CachedBlockInfo());
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestBlockIndexByBlockHash(const Crypto::Hash &blockHash)
{
    state.blockIndexesByBlockHashes.emplace(blockHash, 0);
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestKeyOutputGlobalIndexesCountForAmount(IBlockchainCache::Amount amount)
{
    state.keyOutputGlobalIndexesCountForAmounts.emplace(amount, 0);
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestKeyOutputGlobalIndexForAmount(
    IBlockchainCache::Amount amount,
    uint32_t outputIndexWithinAmout)
{
    state.keyOutputGlobalIndexesForAmounts.emplace(std::make_pair(amount, outputIndexWithinAmout), PackedOutIndex());
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestRawBlock(uint32_t blockIndex)
{
    state.rawBlocks.emplace(blockIndex, RawBlock());
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestRawBlocks(uint64_t startHeight, uint64_t endHeight)
{
    for (uint64_t i = startHeight; i < endHeight; i++)
    {
        state.rawBlocks.emplace(i, RawBlock());
    }

    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestLastBlockIndex()
{
    state.lastBlockIndex.second = true;
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestClosestTimestampBlockIndex(uint64_t timestamp)
{
    state.closestTimestampBlockIndex[timestamp];
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestKeyOutputAmountsCount()
{
    state.keyOutputAmountsCount.second = true;
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestTransactionCountByPaymentId(const Crypto::Hash &paymentId)
{
    state.transactionCountsByPaymentIds.emplace(paymentId, 0);
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestTransactionHashByPaymentId(
    const Crypto::Hash &paymentId,
    uint32_t transactionIndexWithinPaymentId)
{
    state.transactionHashesByPaymentIds.emplace(
        std::make_pair(paymentId, transactionIndexWithinPaymentId), Constants::NULL_HASH);
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestBlockHashesByTimestamp(uint64_t timestamp)
{
    state.blockHashesByTimestamp.emplace(timestamp, std::vector<Crypto::Hash>());
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestTransactionsCount()
{
    state.transactionsCount.second = true;
    return *this;
}

BlockchainReadBatch &BlockchainReadBatch::requestKeyOutputInfo(
    IBlockchainCache::Amount amount,
    IBlockchainCache::GlobalOutputIndex globalIndex)
{
    state.keyOutputKeys.emplace(std::make_pair(amount, globalIndex), KeyOutputInfo {});
    return *this;
}

BlockchainReadResult BlockchainReadBatch::extractResult()
{
    assert(resultSubmitted);
    auto st = std::move(state);
    state.lastBlockIndex = {0, false};
    state.keyOutputAmountsCount = {{}, false};

    resultSubmitted = false;
    return BlockchainReadResult(st);
}

std::vector<std::string> BlockchainReadBatch::getRawKeys() const
{
    std::vector<std::string> rawKeys;
    rawKeys.reserve(state.size());

    DB::serializeKeys(rawKeys, DB::BLOCK_INDEX_TO_KEY_IMAGE_PREFIX, state.spentKeyImagesByBlock);
    DB::serializeKeys(rawKeys, DB::KEY_IMAGE_TO_BLOCK_INDEX_PREFIX, state.blockIndexesBySpentKeyImages);
    DB::serializeKeys(rawKeys, DB::TRANSACTION_HASH_TO_TRANSACTION_INFO_PREFIX, state.cachedTransactions);
    DB::serializeKeys(rawKeys, DB::BLOCK_INDEX_TO_TX_HASHES_PREFIX, state.transactionHashesByBlocks);
    DB::serializeKeys(rawKeys, DB::BLOCK_INDEX_TO_BLOCK_INFO_PREFIX, state.cachedBlocks);
    DB::serializeKeys(rawKeys, DB::BLOCK_HASH_TO_BLOCK_INDEX_PREFIX, state.blockIndexesByBlockHashes);
    DB::serializeKeys(rawKeys, DB::KEY_OUTPUT_AMOUNT_PREFIX, state.keyOutputGlobalIndexesCountForAmounts);
    DB::serializeKeys(rawKeys, DB::KEY_OUTPUT_AMOUNT_PREFIX, state.keyOutputGlobalIndexesForAmounts);
    DB::serializeKeys(rawKeys, DB::BLOCK_INDEX_TO_RAW_BLOCK_PREFIX, state.rawBlocks);
    DB::serializeKeys(rawKeys, DB::CLOSEST_TIMESTAMP_BLOCK_INDEX_PREFIX, state.closestTimestampBlockIndex);
    DB::serializeKeys(rawKeys, DB::KEY_OUTPUT_AMOUNTS_COUNT_PREFIX, state.keyOutputAmounts);
    DB::serializeKeys(rawKeys, DB::PAYMENT_ID_TO_TX_HASH_PREFIX, state.transactionCountsByPaymentIds);
    DB::serializeKeys(rawKeys, DB::PAYMENT_ID_TO_TX_HASH_PREFIX, state.transactionHashesByPaymentIds);
    DB::serializeKeys(rawKeys, DB::TIMESTAMP_TO_BLOCKHASHES_PREFIX, state.blockHashesByTimestamp);
    DB::serializeKeys(rawKeys, DB::KEY_OUTPUT_KEY_PREFIX, state.keyOutputKeys);

    if (state.lastBlockIndex.second)
    {
        rawKeys.emplace_back(DB::serializeKey(DB::BLOCK_INDEX_TO_BLOCK_HASH_PREFIX, DB::LAST_BLOCK_INDEX_KEY));
    }

    if (state.keyOutputAmountsCount.second)
    {
        rawKeys.emplace_back(DB::serializeKey(DB::KEY_OUTPUT_AMOUNTS_COUNT_PREFIX, DB::KEY_OUTPUT_AMOUNTS_COUNT_KEY));
    }

    if (state.transactionsCount.second)
    {
        rawKeys.emplace_back(
            DB::serializeKey(DB::TRANSACTION_HASH_TO_TRANSACTION_INFO_PREFIX, DB::TRANSACTIONS_COUNT_KEY));
    }

    return rawKeys;
}

BlockchainReadResult::BlockchainReadResult(BlockchainReadState _state): state(std::move(_state)) {}

BlockchainReadResult::~BlockchainReadResult() {}

const std::unordered_map<uint32_t, std::vector<Crypto::KeyImage>> &
    BlockchainReadResult::getSpentKeyImagesByBlock() const
{
    return state.spentKeyImagesByBlock;
}

const std::unordered_map<Crypto::KeyImage, uint32_t> &BlockchainReadResult::getBlockIndexesBySpentKeyImages() const
{
    return state.blockIndexesBySpentKeyImages;
}

const std::unordered_map<Crypto::Hash, ExtendedTransactionInfo> &BlockchainReadResult::getCachedTransactions() const
{
    return state.cachedTransactions;
}

const std::unordered_map<uint32_t, std::vector<Crypto::Hash>> &
    BlockchainReadResult::getTransactionHashesByBlocks() const
{
    return state.transactionHashesByBlocks;
}

const std::unordered_map<uint32_t, CachedBlockInfo> &BlockchainReadResult::getCachedBlocks() const
{
    return state.cachedBlocks;
}

const std::unordered_map<Crypto::Hash, uint32_t> &BlockchainReadResult::getBlockIndexesByBlockHashes() const
{
    return state.blockIndexesByBlockHashes;
}

const std::unordered_map<IBlockchainCache::Amount, uint32_t> &
    BlockchainReadResult::getKeyOutputGlobalIndexesCountForAmounts() const
{
    return state.keyOutputGlobalIndexesCountForAmounts;
}

const std::unordered_map<std::pair<IBlockchainCache::Amount, uint32_t>, PackedOutIndex> &
    BlockchainReadResult::getKeyOutputGlobalIndexesForAmounts() const
{
    return state.keyOutputGlobalIndexesForAmounts;
}

const std::unordered_map<uint32_t, RawBlock> &BlockchainReadResult::getRawBlocks() const
{
    return state.rawBlocks;
}

const std::pair<uint32_t, bool> &BlockchainReadResult::getLastBlockIndex() const
{
    return state.lastBlockIndex;
}

const std::unordered_map<uint64_t, uint32_t> &BlockchainReadResult::getClosestTimestampBlockIndex() const
{
    return state.closestTimestampBlockIndex;
}

uint32_t BlockchainReadResult::getKeyOutputAmountsCount() const
{
    return state.keyOutputAmountsCount.first;
}

const std::unordered_map<Crypto::Hash, uint32_t> &BlockchainReadResult::getTransactionCountByPaymentIds() const
{
    return state.transactionCountsByPaymentIds;
}

const std::unordered_map<std::pair<Crypto::Hash, uint32_t>, Crypto::Hash> &
    BlockchainReadResult::getTransactionHashesByPaymentIds() const
{
    return state.transactionHashesByPaymentIds;
}

const std::unordered_map<uint64_t, std::vector<Crypto::Hash>> &BlockchainReadResult::getBlockHashesByTimestamp() const
{
    return state.blockHashesByTimestamp;
}

const std::pair<uint64_t, bool> &BlockchainReadResult::getTransactionsCount() const
{
    return state.transactionsCount;
}

const KeyOutputKeyResult &BlockchainReadResult::getKeyOutputInfo() const
{
    return state.keyOutputKeys;
}

void BlockchainReadBatch::submitRawResult(const std::vector<std::string> &values, const std::vector<bool> &resultStates)
{
    assert(state.size() == values.size());
    assert(values.size() == resultStates.size());
    auto range = boost::combine(values, resultStates);
    auto iter = range.begin();

    DB::deserializeValues(state.spentKeyImagesByBlock, iter, DB::BLOCK_INDEX_TO_KEY_IMAGE_PREFIX);
    DB::deserializeValues(state.blockIndexesBySpentKeyImages, iter, DB::KEY_IMAGE_TO_BLOCK_INDEX_PREFIX);
    DB::deserializeValues(state.cachedTransactions, iter, DB::TRANSACTION_HASH_TO_TRANSACTION_INFO_PREFIX);
    DB::deserializeValues(state.transactionHashesByBlocks, iter, DB::BLOCK_INDEX_TO_TX_HASHES_PREFIX);
    DB::deserializeValues(state.cachedBlocks, iter, DB::BLOCK_INDEX_TO_BLOCK_INFO_PREFIX);
    DB::deserializeValues(state.blockIndexesByBlockHashes, iter, DB::BLOCK_HASH_TO_BLOCK_INDEX_PREFIX);
    DB::deserializeValues(state.keyOutputGlobalIndexesCountForAmounts, iter, DB::KEY_OUTPUT_AMOUNT_PREFIX);
    DB::deserializeValues(state.keyOutputGlobalIndexesForAmounts, iter, DB::KEY_OUTPUT_AMOUNT_PREFIX);
    DB::deserializeValues(state.rawBlocks, iter, DB::BLOCK_INDEX_TO_RAW_BLOCK_PREFIX);
    DB::deserializeValues(state.closestTimestampBlockIndex, iter, DB::CLOSEST_TIMESTAMP_BLOCK_INDEX_PREFIX);
    DB::deserializeValues(state.keyOutputAmounts, iter, DB::KEY_OUTPUT_AMOUNTS_COUNT_PREFIX);
    DB::deserializeValues(state.transactionCountsByPaymentIds, iter, DB::PAYMENT_ID_TO_TX_HASH_PREFIX);
    DB::deserializeValues(state.transactionHashesByPaymentIds, iter, DB::PAYMENT_ID_TO_TX_HASH_PREFIX);
    DB::deserializeValues(state.blockHashesByTimestamp, iter, DB::TIMESTAMP_TO_BLOCKHASHES_PREFIX);
    DB::deserializeValues(state.keyOutputKeys, iter, DB::KEY_OUTPUT_KEY_PREFIX);

    DB::deserializeValue(state.lastBlockIndex, iter, DB::BLOCK_INDEX_TO_BLOCK_HASH_PREFIX);
    DB::deserializeValue(state.keyOutputAmountsCount, iter, DB::KEY_OUTPUT_AMOUNTS_COUNT_PREFIX);
    DB::deserializeValue(state.transactionsCount, iter, DB::TRANSACTION_HASH_TO_TRANSACTION_INFO_PREFIX);

    assert(iter == range.end());

    resultSubmitted = true;
}

BlockchainReadState::BlockchainReadState(BlockchainReadState &&state):
    spentKeyImagesByBlock(std::move(state.spentKeyImagesByBlock)),
    blockIndexesBySpentKeyImages(std::move(state.blockIndexesBySpentKeyImages)),
    cachedTransactions(std::move(state.cachedTransactions)),
    transactionHashesByBlocks(std::move(state.transactionHashesByBlocks)),
    cachedBlocks(std::move(state.cachedBlocks)),
    blockIndexesByBlockHashes(std::move(state.blockIndexesByBlockHashes)),
    keyOutputGlobalIndexesCountForAmounts(std::move(state.keyOutputGlobalIndexesCountForAmounts)),
    keyOutputGlobalIndexesForAmounts(std::move(state.keyOutputGlobalIndexesForAmounts)),
    rawBlocks(std::move(state.rawBlocks)),
    blockHashesByTimestamp(std::move(state.blockHashesByTimestamp)),
    keyOutputKeys(std::move(state.keyOutputKeys)),
    closestTimestampBlockIndex(std::move(state.closestTimestampBlockIndex)),
    lastBlockIndex(std::move(state.lastBlockIndex)),
    keyOutputAmountsCount(std::move(state.keyOutputAmountsCount)),
    keyOutputAmounts(std::move(state.keyOutputAmounts)),
    transactionCountsByPaymentIds(std::move(state.transactionCountsByPaymentIds)),
    transactionHashesByPaymentIds(std::move(state.transactionHashesByPaymentIds)),
    transactionsCount(std::move(state.transactionsCount))
{
}

size_t BlockchainReadState::size() const
{
    return spentKeyImagesByBlock.size() + blockIndexesBySpentKeyImages.size() + cachedTransactions.size()
           + transactionHashesByBlocks.size() + cachedBlocks.size() + blockIndexesByBlockHashes.size()
           + keyOutputGlobalIndexesCountForAmounts.size() + keyOutputGlobalIndexesForAmounts.size() + rawBlocks.size()
           + closestTimestampBlockIndex.size() + keyOutputAmounts.size() + transactionCountsByPaymentIds.size()
           + transactionHashesByPaymentIds.size() + blockHashesByTimestamp.size() + keyOutputKeys.size()
           + (lastBlockIndex.second ? 1 : 0) + (keyOutputAmountsCount.second ? 1 : 0)
           + (transactionsCount.second ? 1 : 0);
}

BlockchainReadResult::BlockchainReadResult(BlockchainReadResult &&result): state(std::move(result.state)) {}

max_stars_repo_name: ProximusPXS/Proximus

max_issues_repo_name: ProximusPXS/Proximus

max_forks_repo_name: ProximusPXS/Proximus


text:
/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#include <eosio/chain/contracts/chain_initializer.hpp>
#include <eosio/chain/contracts/objects.hpp>
#include <eosio/chain/contracts/eos_contract.hpp>
#include <eosio/chain/contracts/types.hpp>

#include <eosio/chain/producer_object.hpp>
#include <eosio/chain/permission_object.hpp>

#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>

namespace eosio { namespace chain { namespace contracts {

time_point chain_initializer::get_chain_start_time() {
   return genesis.initial_timestamp;
}

chain_config chain_initializer::get_chain_start_configuration() {
   return genesis.initial_configuration;
}

producer_schedule_type chain_initializer::get_chain_start_producers() {
   producer_schedule_type result;
   std::transform(genesis.initial_producers.begin(), genesis.initial_producers.end(), result.producers.begin(),
                  [](const auto& p) { return producer_key{p.owner_name,p.block_signing_key}; });
   return result;
}

void chain_initializer::register_types(chain_controller& chain, chainbase::database& db) {
   // Install the native contract's indexes; we can't do anything until our objects are recognized
   db.add_index<staked_balance_multi_index>();
   db.add_index<producer_votes_multi_index>();

#define SET_APP_HANDLER( contract, scope, action, nspace ) \
   chain._set_apply_handler( #contract, #scope, #action, &BOOST_PP_CAT(contracts::apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) )

   SET_APP_HANDLER( eosio, eosio, setproducer, eosio );
   SET_APP_HANDLER( eosio, eosio, newaccount, eosio );
   SET_APP_HANDLER( eosio, eosio, transfer, eosio );
   SET_APP_HANDLER( eosio, eosio, lock, eosio );
   SET_APP_HANDLER( eosio, eosio, claim, eosio );
   SET_APP_HANDLER( eosio, eosio, unlock, eosio );
   SET_APP_HANDLER( eosio, eosio, okproducer, eosio );
   SET_APP_HANDLER( eosio, eosio, setproxy, eosio );
   SET_APP_HANDLER( eosio, eosio, setcode, eosio );
   SET_APP_HANDLER( eosio, eosio, setabi, eosio );
   SET_APP_HANDLER( eosio, eosio, updateauth, eosio );
   SET_APP_HANDLER( eosio, eosio, deleteauth, eosio );
   SET_APP_HANDLER( eosio, eosio, linkauth, eosio );
   SET_APP_HANDLER( eosio, eosio, unlinkauth, eosio );
   SET_APP_HANDLER( eosio, eosio, nonce, eosio );
   SET_APP_HANDLER( eosio, eosio, onerror, eosio );
   SET_APP_HANDLER( eosio, eosio, postrecovery, eosio );
   SET_APP_HANDLER( eosio, eosio, passrecovery, eosio );
   SET_APP_HANDLER( eosio, eosio, vetorecovery, eosio );
}

abi_def chain_initializer::eos_contract_abi()
{
   abi_def eos_abi;
   eos_abi.types.push_back( type_def{"account_name","name"} );
   eos_abi.types.push_back( type_def{"share_type","int64"} );
   eos_abi.types.push_back( type_def{"onerror","bytes"} );
   eos_abi.actions.push_back( action_def{name("transfer"), "transfer"} );
   eos_abi.actions.push_back( action_def{name("lock"), "lock"} );
   eos_abi.actions.push_back( action_def{name("unlock"), "unlock"} );
   eos_abi.actions.push_back( action_def{name("claim"), "claim"} );
   eos_abi.actions.push_back( action_def{name("okproducer"), "okproducer"} );
   eos_abi.actions.push_back( action_def{name("setproducer"), "setproducer"} );
   eos_abi.actions.push_back( action_def{name("setproxy"), "setproxy"} );
   eos_abi.actions.push_back( action_def{name("setcode"), "setcode"} );
   eos_abi.actions.push_back( action_def{name("setabi"), "setabi"} );
   eos_abi.actions.push_back( action_def{name("linkauth"), "linkauth"} );
   eos_abi.actions.push_back( action_def{name("unlinkauth"), "unlinkauth"} );
   eos_abi.actions.push_back( action_def{name("updateauth"), "updateauth"} );
   eos_abi.actions.push_back( action_def{name("deleteauth"), "deleteauth"} );
   eos_abi.actions.push_back( action_def{name("newaccount"), "newaccount"} );
   eos_abi.actions.push_back( action_def{name("postrecovery"), "postrecovery"} );
   eos_abi.actions.push_back( action_def{name("passrecovery"), "passrecovery"} );
   eos_abi.actions.push_back( action_def{name("vetorecovery"), "vetorecovery"} );
   eos_abi.actions.push_back( action_def{name("onerror"), "onerror"} );
   eos_abi.actions.push_back( action_def{name("nonce"), "nonce"} );

   // ACTION PAYLOADS
   eos_abi.structs.emplace_back( struct_def {
      "transfer", "", {
         {"from", "account_name"},
         {"to", "account_name"},
         {"amount", "uint64"},
         {"memo", "string"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "lock", "", {
         {"from", "account_name"},
         {"to", "account_name"},
         {"amount", "share_type"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "unlock", "", {
         {"account", "account_name"},
         {"amount", "share_type"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "claim", "", {
         {"account", "account_name"},
         {"amount", "share_type"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "okproducer", "", {
         {"voter", "account_name"},
         {"producer", "account_name"},
         {"approve", "int8"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "setproducer", "", {
         {"name", "account_name"},
         {"key", "public_key"},
         {"configuration", "chain_config"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "setproxy", "", {
         {"stakeholder", "account_name"},
         {"proxy", "account_name"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "setcode", "", {
         {"account", "account_name"},
         {"vmtype", "uint8"},
         {"vmversion", "uint8"},
         {"code", "bytes"}
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "setabi", "", {
         {"account", "account_name"},
         {"abi", "abi_def"}
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "updateauth", "", {
         {"account", "account_name"},
         {"permission", "permission_name"},
         {"parent", "permission_name"},
         {"data", "authority"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "linkauth", "", {
         {"account", "account_name"},
         {"code", "account_name"},
         {"type", "action_name"},
         {"requirement", "permission_name"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "unlinkauth", "", {
         {"account", "account_name"},
         {"code", "account_name"},
         {"type", "action_name"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "deleteauth", "", {
         {"account", "account_name"},
         {"permission", "permission_name"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "newaccount", "", {
         {"creator", "account_name"},
         {"name", "account_name"},
         {"owner", "authority"},
         {"active", "authority"},
         {"recovery", "authority"},
         {"deposit", "asset"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "postrecovery", "", {
         {"account", "account_name"},
         {"data", "authority"},
         {"memo", "string"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "passrecovery", "", {
         {"account", "account_name"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "vetorecovery", "", {
         {"account", "account_name"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "nonce", "", {
         {"value", "name"}
      }
   });

   // DATABASE RECORDS
   eos_abi.structs.emplace_back( struct_def {
      "account", "", {
         {"key",     "name"},
         {"balance", "uint64"},
      }
   });

   eos_abi.structs.emplace_back( struct_def {
      "pending_recovery", "", {
         {"account",    "name"},
         {"request_id", "uint32"},
         {"update",     "updateauth"},
         {"memo",       "string"}
      }
   });

   eos_abi.tables.emplace_back( table_def {
      "currency", "i64", {
         "key"
      }, {
         "name"
      },
      "account"
   });

   eos_abi.tables.emplace_back( table_def {
      "recovery", "i64", {
         "account",
      }, {
         "name"
      },
      "pending_recovery"
   });

   return eos_abi;
}

// forward declared method from eosio contract
void intialize_eosio_tokens(chainbase::database& db, const account_name& system_account, share_type initial_tokens);

std::vector<action> chain_initializer::prepare_database( chain_controller& chain,
                                                         chainbase::database& db) {
   std::vector<action> messages_to_process;

   /// Create the native contract accounts manually; sadly, we can't run their contracts to make them create themselves
   auto create_native_account = [this, &db](account_name name, auto liquid_balance) {
      db.create<account_object>([this, &name](account_object& a) {
         a.name = name;
         a.creation_date = genesis.initial_timestamp;

         if( name == config::system_account_name ) {
            a.set_abi(eos_contract_abi());
         }
      });
      const auto& owner = db.create<permission_object>([&name](permission_object& p) {
         p.owner = name;
         p.name = "owner";
         p.auth.threshold = 1;
      });
      db.create<permission_object>([&name, &owner](permission_object& p) {
         p.owner = name;
         p.parent = owner.id;
         p.name = "active";
         p.auth.threshold = 1;
      });
      intialize_eosio_tokens(db, name, liquid_balance);
      db.create<staked_balance_object>([&](auto& sb) { sb.owner_name = name; });
      db.create<bandwidth_usage_object>([&](auto& sb) { sb.owner = name; });
   };
   create_native_account(config::system_account_name, config::initial_token_supply);

   // Queue up messages which will run contracts to create the initial accounts
   for (const auto& acct : genesis.initial_accounts) {
      action message( {{config::system_account_name, config::active_name}},
                      newaccount{ config::system_account_name, acct.name,
                                                             authority(acct.owner_key),
                                                             authority(acct.active_key),
                                                             authority(acct.owner_key),
                                                             acct.staking_balance});

      messages_to_process.emplace_back(move(message));

      if (acct.liquid_balance > 0) {
         message = action( {{config::system_account_name, config::active_name}},
                           transfer{ .from = config::system_account_name, .to = acct.name,
                                     .amount = acct.liquid_balance.amount, .memo = "Genesis Allocation"});
         messages_to_process.emplace_back(move(message));
      }
   }

   // Create initial producers
   auto create_producer = boost::adaptors::transformed([config = genesis.initial_configuration](const auto& p) {
      return action( {{p.owner_name, config::active_name}},
                     setproducer(p.owner_name, p.block_signing_key, config));
   });
   boost::copy(genesis.initial_producers | create_producer, std::back_inserter(messages_to_process));

   // Create special accounts
   auto create_special_account = [this, &db](account_name name, const auto& owner, const auto& active) {
      db.create<account_object>([this, &name](account_object& a) {
         a.name = name;
         a.creation_date = genesis.initial_timestamp;
      });
      const auto& owner_permission = db.create<permission_object>([&owner, &name](permission_object& p) {
         p.name = config::owner_name;
         p.parent = 0;
         p.owner = name;
         p.auth = move(owner);
      });
      db.create<permission_object>([&active, &owner_permission](permission_object& p) {
         p.name = config::active_name;
         p.parent = owner_permission.id;
         p.owner = owner_permission.owner;
         p.auth = move(active);
      });
   };

   auto empty_authority = authority(0, {}, {});
   auto active_producers_authority = authority(config::producers_authority_threshold, {}, {});
   for(auto& p : genesis.initial_producers) {
      active_producers_authority.accounts.push_back({{p.owner_name, config::active_name}, 1});
   }

   create_special_account(config::nobody_account_name, empty_authority, empty_authority);
   create_special_account(config::producers_account_name, empty_authority, active_producers_authority);

   return messages_to_process;
}

} } } // namespace eosio::chain::contracts

max_stars_repo_name: anauman/eosio

max_issues_repo_name: anauman/eosio

max_forks_repo_name: anauman/eosio


text:
/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2017 by Rokko Developers https://github.com/t-sakashita/rokko
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*****************************************************************************/

#ifndef ROKKO_EIGEN3_HPP
#define ROKKO_EIGEN3_HPP

#include <rokko/eigen3/matrix_major.hpp>
#include <Eigen/Dense>

namespace Eigen {

template<typename T, int ROWS, int MATRIX_MAJOR>
int size(Eigen::Matrix<T, ROWS, 1, MATRIX_MAJOR> const& vec) {
  return vec.size();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
bool is_col_major(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR> const&) {
  return MATRIX_MAJOR == Eigen::ColMajor;
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
bool is_row_major(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR> const&) {
  return MATRIX_MAJOR == Eigen::RowMajor;
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
int rows(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR> const& mat) {
  return mat.rows();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
int cols(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR> const& mat) {
  return mat.cols();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
int ld(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR> const& mat) {
  return mat.innerSize();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
const T* storage(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR> const& mat) {
  return mat.data();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
T* storage(Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR>& mat) {
  return mat.data();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
const T* storage(Eigen::Ref<Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR>> const& mat) {
  return mat.data();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
T* storage(Eigen::Ref<Eigen::Matrix<T, ROWS, COLS, MATRIX_MAJOR>>& mat) {
  return mat.data();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
const std::complex<T>* storage(Eigen::Matrix<std::complex<T>, ROWS, COLS, MATRIX_MAJOR> const& mat) {
  return mat.data();
}

template<typename T, int ROWS, int COLS, int MATRIX_MAJOR>
std::complex<T>* storage(Eigen::Matrix<std::complex<T>, ROWS, COLS, MATRIX_MAJOR>& mat) {
  return mat.data();
}

template<typename T, int ROWS = Eigen::Dynamic>
using Vector = Eigen::Matrix<T, ROWS, 1>;

template<typename T>
using RefVec = Eigen::Ref<Vector<T>>;

} // namespace Eigen

#endif // ROKKO_EIGEN3_HPP

max_stars_repo_name: t-sakashita/rokko

max_issues_repo_name: t-sakashita/rokko

max_forks_repo_name: t-sakashita/rokko


text:
//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T.Lapreste

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_DEFINITION_SELINC_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_DEFINITION_SELINC_HPP_INCLUDED

#include <boost/simd/config.hpp>
#include <boost/dispatch/function/make_callable.hpp>
#include <boost/dispatch/hierarchy/functions.hpp>
#include <boost/simd/detail/dispatch.hpp>

namespace boost { namespace simd
{
  namespace tag
  {
    BOOST_DISPATCH_MAKE_TAG(ext, selinc_, boost::dispatch::elementwise_<selinc_>);
  }

  namespace ext
  {
    BOOST_DISPATCH_FUNCTION_DECLARATION(tag, selinc_);
  }

  BOOST_DISPATCH_CALLABLE_DEFINITION(tag::selinc_,selinc);

} }

#endif


text:
#include "factory.h"
#include <iostream>
#include <vector>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <boost/core/demangle.hpp>
#include <functional>

using PCXYZ = pcl::PointCloud<pcl::PointXYZ>;

int main() {
    std::vector<double> data;
    auto a = Build<Remover<pcl::PointXYZ>>("PatchWorkRemover",data); //Factory<Remover<pcl::PointXYZ>>::Build(REGISTER_NAME("PatchWorkRemover", pcl::PointXYZ), data);
    auto b =  Build<Remover<pcl::PointXYZ>>("RansacRemover",data);//Factory<Remover<pcl::PointXYZ>>::Build(REGISTER_NAME("RansacRemover", pcl::PointXYZ), data);
    auto c =  Build<Cluster>("IntRemover",data); //Factory<Cluster>::Build(REGISTER_NAME("IntRemover"), data);

    a->filter(pcl::PointXYZ{1,2,3});
    b->filter(pcl::PointXYZ{1,2,3});
    c->filter(1);

//    std::cout << full_type_name<template_traits<Remover<pcl::PointXYZ>>::type<0>>() << std::endl;
//    std::cout << full_type_name<template_traits<Remover<pcl::PointXYZ>>::class_type>() << std::endl;
//    std::cout << template_traits<Cluster>::size << std::endl;
    return 0;
}


text:
/*!======================================================================
   Feature Selection Toolbox 3 source code
   ---------------------------------------

   \file    global.cpp
   \brief   Global definitions
   \author  Petr Somol (somol@utia.cas.cz) with collaborators, see Contacts at http://fst.utia.cz
   \date    March 2011
   \version 3.1.0.beta
   \note    FST3 was developed using gcc 4.3 and requires
   \note    \li Boost library (http://www.boost.org/, tested with versions 1.33.1 and 1.44),
   \note    \li (\e optionally) LibSVM (http://www.csie.ntu.edu.tw/~cjlin/libsvm/,
                tested with version 3.00)
   \note    Note that LibSVM is required for SVM related tools only,
            as demonstrated in demo12t.cpp, demo23.cpp, demo25t.cpp, demo32t.cpp, etc.

*/ /*
=========================================================================
Copyright:
  * FST3 software (with exception of any externally linked libraries)
    is copyrighted by Institute of Information Theory and Automation (UTIA),
    Academy of Sciences of the Czech Republic.
  * FST3 source codes as presented here do not contain code of third parties.
    FST3 may need linkage to external libraries to exploit its functionality
    in full. For details on obtaining and possible usage restrictions
    of external libraries follow their original sources (referenced from
    FST3 documentation wherever applicable).
  * FST3 software is available free of charge for non-commercial use.
    Please address all inquires concerning possible commercial use
    of FST3, or if in doubt, to FST3 maintainer (see http://fst.utia.cz).
  * Derivative works based on FST3 are permitted as long as they remain
    non-commercial only.
  * Re-distribution of FST3 software is not allowed without explicit
    consent of the copyright holder.
Disclaimer of Warranty:
  * FST3 software is presented "as is", without warranty of any kind,
    either expressed or implied, including, but not limited to, the implied
    warranties of merchantability and fitness for a particular purpose.
    The entire risk as to the quality and performance of the program
    is with you. Should the program prove defective, you assume the cost
    of all necessary servicing, repair or correction.
Limitation of Liability:
  * The copyright holder will in no event be liable to you for damages,
    including any general, special, incidental or consequential damages
    arising out of the use or inability to use the code (including but not
    limited to loss of data or data being rendered inaccurate or losses
    sustained by you or third parties or a failure of the program to operate
    with any other programs).
========================================================================== */

#include <iostream>
#include <string>
#include <sstream>
#ifdef FST_THREADED
#include <boost/thread/mutex.hpp>
#endif
#include "global.hpp"

namespace FST {

#ifdef FST_THREADED
boost::mutex *syncout::io_mutex = NULL;
#endif

void notify(const string msg)
{
#ifdef DEBUG
	std::ostringstream ss;
	ss << msg << std::endl;
	syncout::print(std::cout,ss);
#endif
}

void notify(const string msg1, const double num, const string msg2)
{
#ifdef DEBUG
	std::ostringstream ss;
	ss << msg1 << num << msg2 << std::endl;
	syncout::print(std::cout,ss);
#endif
}

void notify(const string msg1, const double num1, const string msg2, const double num2, const string msg3)
{
#ifdef DEBUG
	std::ostringstream ss;
	ss << msg1 << num1 << msg2 << num2 << msg3 << std::endl;
	syncout::print(std::cout,ss);
#endif
}

void notify(const string msg1, const double num1, const string msg2, const double num2, const string msg3, const double num3, const string msg4)
{
#ifdef DEBUG
	std::ostringstream ss;
	ss << msg1 << num1 << msg2 << num2 << msg3 << num3 << msg4 << std::endl;
	syncout::print(std::cout,ss);
#endif
}

} //namespace

max_stars_repo_name: boussaffawalid/FeatureSelection

max_issues_repo_name: boussaffawalid/FeatureSelection

max_forks_repo_name: boussaffawalid/FeatureSelection