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

#include <random>
#include <stdexcept>

#include "xmeans_coordinator.hpp"

#include "xmeans.hpp"

#include "io.hpp"
#include "clusters.hpp"
#include "hclust_id_generator.hpp"

namespace knor {

    xmeans_coordinator::xmeans_coordinator(const std::string fn,
            const size_t nrow,
            const size_t ncol, const unsigned k, const unsigned max_iters,
            const unsigned nnodes, const unsigned nthreads,
            const double* centers, const base::init_t it,
            const double tolerance, const base::dist_t dt,
            const unsigned min_clust_size) :
        hclust_coordinator(fn, nrow, ncol, k, max_iters, nnodes, nthreads,
                centers, it, tolerance, dt, min_clust_size) {

            partition_dist.resize(nrow);
            nearest_cdist.resize(nrow);
            // TODO: k can be non 2^n
            cltrs = kbase::clusters::create(
                    base::get_max_hnodes(this->k), ncol);
    }

void xmeans_coordinator::build_thread_state() {
    // NUMA node affinity binding policy is round-robin
    unsigned thds_row = nrow / nthreads;

    for (unsigned thd_id = 0; thd_id < nthreads; thd_id++) {
        std::pair<unsigned, unsigned> tup = get_rid_len_tup(thd_id);
        thd_max_row_idx.push_back((thd_id*thds_row) + tup.second);
        threads.push_back(xmeans::create((thd_id % nnodes),
                    thd_id, tup.first, tup.second,
                    ncol, k, hcltrs, &cluster_assignments[0], fn,
                    _dist_t, cltr_active_vec, partition_dist, nearest_cdist,
                    compute_pdist));
        threads[thd_id]->set_parent_cond(&cond);
        threads[thd_id]->set_parent_pending_threads(&pending_threads);
        threads[thd_id]->start(WAIT); // Thread puts itself to sleep
        std::static_pointer_cast<xmeans>(threads[thd_id])
                    ->set_part_id(&part_id[0]);
        std::static_pointer_cast<xmeans>(threads[thd_id])
                    ->set_g_clusters(cltrs);
    }
}

void xmeans_coordinator::combine_partition_means() {
    cltrs->unfinalize_all();

    for (auto const& th : threads) {
        auto thd_lcltrs = th->get_local_clusters();
        cltrs->peq(thd_lcltrs);
    }
    cltrs->finalize_all();
}

 /**
   This function computes BIC for parent and children
 We use:
     cltrs -- parent cluster values
     hcltrs -- children values
     nearest_cdist -- data point-assigned cluster dist
     partition dist -- data point-partition dist
 */
void xmeans_coordinator::bic(split_score_t& score,
        std::unordered_map<unsigned, std::vector<unsigned>>& memb_cltrs) {

    // Compute for parent
    double pK = 1; // parent K
    double cK = 2; // children K
    double N = cluster_assignment_counts[score.lid]
                        + cluster_assignment_counts[score.rid];
    double psigma = 0;
    double csigma = 0;

    for (auto const& idx : memb_cltrs[score.lid]) {
            psigma += partition_dist[idx];
            csigma += nearest_cdist[idx];
    }

    for (auto const& idx : memb_cltrs[score.rid]) {
            psigma += partition_dist[idx];
            csigma += nearest_cdist[idx];
    }

    // Parent
    if (N - pK > 0) {
        psigma /= (double) (N - pK);
        double p = (pK - 1) + ncol * pK + 1;

        /* splitting criterion */
        double L = N * std::log(N) - N * std::log(N) - N *
            std::log(2.0 * PI) * .5 - N * ncol *
            std::log(psigma) * .5 - (N - pK) * .5;

        score.pscore = L - p * 0.5 * std::log(N);
    }

    // Children
    if (N - cK > 0) {
        csigma /= (double) (N - cK);
        double p = (cK - 1) + ncol * cK + 1;

        /* splitting criterion */
        double nl = cluster_assignment_counts[score.lid];
        double L = N * std::log(N) - nl * std::log(N) - N *
            std::log(2.0 * PI) * .5 - N * ncol *
            std::log(csigma) * .5 - (N - cK) * .5;

        score.cscore = L - p * 0.5 * std::log(N);

        double nr = cluster_assignment_counts[score.lid];
        L = N * std::log(N) - nr * std::log(N) - N *
            std::log(2.0 * PI) * .5- N * ncol *
            std::log(csigma) * .5 - (N - cK) * .5;
        score.cscore += L - p * .5 * std::log(N);
    }
}

void xmeans_coordinator::compute_bic_scores(
        std::vector<split_score_t>& bic_scores,
    std::unordered_map<unsigned, std::vector<unsigned>>& memb_cltrs) {

    // Creates structures to store bic scores & cluster membership
    auto itr = hcltrs.get_iterator();
    while (itr.has_next()) {
        auto kv = itr.next();
        assert(kv.first == kv.second->get_id());
#if 1
        printf("BIC evaluation for pid: %lu, lid: %u, rid: %u\n",
                kv.first, kv.second->get_zeroid(), kv.second->get_oneid());
#endif
        bic_scores.push_back(split_score_t(kv.second->get_id(),
                    kv.second->get_zeroid(), kv.second->get_oneid()));
    }

#if 0
    assert(std::accumulate(cluster_assignment_counts.begin(),
                cluster_assignment_counts.end(), 0)
                        == static_cast<llong_t>(nrow));
#endif

    // TODO: Slow
    // Creates structures to hold cluster membership
    accumulate(cluster_assignments, memb_cltrs);

    // Computes the bic scores for each parent, child combo
#pragma omp parallel for shared (bic_scores) schedule (dynamic)
    for (size_t idx = 0; idx < bic_scores.size(); idx++) {
        bic(bic_scores[idx], memb_cltrs);
    }
}

// NOTE: This modifies hcltrs
void xmeans_coordinator::partition_decision() {
    std::vector<split_score_t> bic_scores;
    std::unordered_map<unsigned, std::vector<unsigned>> memb_cltrs; // Parent
    compute_bic_scores(bic_scores, memb_cltrs);

    std::vector<bool> remove_cache;
    remove_cache.assign(false, bic_scores.size());

#pragma omp parallel for shared (bic_scores)
    for (size_t i = 0; i < bic_scores.size(); i++) {
        auto score = bic_scores[i];
        if (score.pscore > score.cscore) {
#if 1
            printf("\nPart: %u will NOT split! pscore: %.4f > cscore: %.4f\n",
                    score.pid, score.pscore, score.cscore);
#endif
            // Move all in children clusters to (parent) partition
            auto const& lmembers = memb_cltrs[score.lid];
            for (size_t i = 0; i < memb_cltrs[score.lid].size(); i++)
               cluster_assignments[lmembers[i]] = score.pid;

            auto const& rmembers = memb_cltrs[score.lid];
            for (size_t i = 0; i < memb_cltrs[score.rid].size(); i++)
               cluster_assignments[rmembers[i]] = score.pid;

            // Deactivate both lid and rid
            deactivate(score.lid); deactivate(score.rid);

            // Deactivate pid
            deactivate(score.pid);
            remove_cache[i] = true;
            final_centroids[score.pid] = std::vector<double>(
                    cltrs->get_mean_rawptr(score.pid),
                    cltrs->get_mean_rawptr(score.pid) + ncol);
        } else {
#if 1
            printf("\nPart: %u will split! pscore: %.4f <= cscore: %.4f\n",
                    score.pid, score.pscore, score.cscore);
#endif
        }
    }

    for (size_t i = 0; i < remove_cache.size(); i++) {
        if (remove_cache[i])
            hcltrs.erase(bic_scores[i].pid);
    }
}

// Main driver
base::cluster_t xmeans_coordinator::run(
        double* allocd_data, const bool numa_opt) {
#ifdef PROFILER
    ProfilerStart("xmeans_coordinator.perf");
#endif

    build_thread_state();

    if (!numa_opt && NULL == allocd_data) {
        wake4run(ALLOC_DATA);
        wait4complete();
    } else if (allocd_data) { // No NUMA opt
        set_thread_data_ptr(allocd_data);
    }

    struct timeval start, end;
    gettimeofday(&start , NULL);

    if (_init_t == kbase::init_t::NONE)
        _init_t = kbase::init_t::FORGY;
    run_hinit(); // Initialize clusters

    // Run loop
    size_t iter = 0;

    unsigned curr_nclust = 1;
    while (true) {
        printf("Running a Partition Mean step...\n");
        // TODO: Do this simultaneously with H_EM step
        wake4run(MEAN);
        wait4complete();
        combine_partition_means();
        compute_pdist = true;

        for (iter = 0; iter < max_iters; iter++) {
            printf("\n\nNCLUST: %u, Iteration: %lu\n", curr_nclust, iter);
            // Now pick between the cluster splits
            wake4run(H_EM);
            wait4complete();
            update_clusters();
#if 1
            printf("\nAfter update_clusters ... Global hcltrs:\n");
            print_clusters();
            printf("\nAssignment counts:\n");
            base::sparse_print(cluster_assignment_counts);
            //printf("\nAssignments:\n");
            //base::print(cluster_assignments, nrow);
#endif
            printf("\n*****************************************************\n");
            if (compute_pdist)
                compute_pdist = false;
        }

        // Decide on split or not here
        partition_decision();

        if (curr_nclust >= k*2) {
            printf("\n\nCLUSTER SIZE EXIT @ %u!\n", curr_nclust);
            break;
        }

        // Update global state
        init_splits(); // Initialize possible splits

        // Break when clusters are inactive due to size
        if (hcltrs.keyless()) {
            assert(steady_state()); // NOTE: Comment when benchmarking
            printf("\n\nSTEADY STATE EXIT!\n");
            break;
        }
        curr_nclust = hcltrs.keycount()*2 + final_centroids.size();
    }
#ifdef PROFILER
    ProfilerStop();
#endif

    gettimeofday(&end, NULL);
#ifndef BIND
    printf("\n\nAlgorithmic time taken = %.6f sec\n",
        base::time_diff(start, end));
    printf("\n******************************************\n");
#endif

#ifndef BIND
    printf("Final cluster counts: \n");
    accumulate_cluster_counts();
    base::sparse_print(cluster_assignment_counts);
    printf("\n******************************************\n");
#endif

#if 0
    return base::cluster_t(this->nrow, this->ncol, iter, this->k,
            &cluster_assignments[0], &cluster_assignment_counts[0],
            hcltrs->get_means());
#else
    return base::cluster_t(); // TODO
#endif
}
}
<commit_msg>bug: remove cache had incorrect assignment<commit_after>/*
 * Copyright 2016 neurodata (http://neurodata.io/)
 * Written by Disa Mhembere (disa@jhu.edu)
 *
 * This file is part of knor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY CURRENT_KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <random>
#include <stdexcept>

#include "xmeans_coordinator.hpp"

#include "xmeans.hpp"

#include "io.hpp"
#include "clusters.hpp"
#include "hclust_id_generator.hpp"

namespace knor {

    xmeans_coordinator::xmeans_coordinator(const std::string fn,
            const size_t nrow,
            const size_t ncol, const unsigned k, const unsigned max_iters,
            const unsigned nnodes, const unsigned nthreads,
            const double* centers, const base::init_t it,
            const double tolerance, const base::dist_t dt,
            const unsigned min_clust_size) :
        hclust_coordinator(fn, nrow, ncol, k, max_iters, nnodes, nthreads,
                centers, it, tolerance, dt, min_clust_size) {

            partition_dist.resize(nrow);
            nearest_cdist.resize(nrow);
            // TODO: k can be non 2^n
            cltrs = kbase::clusters::create(
                    base::get_max_hnodes(this->k), ncol);
    }

void xmeans_coordinator::build_thread_state() {
    // NUMA node affinity binding policy is round-robin
    unsigned thds_row = nrow / nthreads;

    for (unsigned thd_id = 0; thd_id < nthreads; thd_id++) {
        std::pair<unsigned, unsigned> tup = get_rid_len_tup(thd_id);
        thd_max_row_idx.push_back((thd_id*thds_row) + tup.second);
        threads.push_back(xmeans::create((thd_id % nnodes),
                    thd_id, tup.first, tup.second,
                    ncol, k, hcltrs, &cluster_assignments[0], fn,
                    _dist_t, cltr_active_vec, partition_dist, nearest_cdist,
                    compute_pdist));
        threads[thd_id]->set_parent_cond(&cond);
        threads[thd_id]->set_parent_pending_threads(&pending_threads);
        threads[thd_id]->start(WAIT); // Thread puts itself to sleep
        std::static_pointer_cast<xmeans>(threads[thd_id])
                    ->set_part_id(&part_id[0]);
        std::static_pointer_cast<xmeans>(threads[thd_id])
                    ->set_g_clusters(cltrs);
    }
}

void xmeans_coordinator::combine_partition_means() {
    cltrs->unfinalize_all();

    for (auto const& th : threads) {
        auto thd_lcltrs = th->get_local_clusters();
        cltrs->peq(thd_lcltrs);
    }
    cltrs->finalize_all();
}

 /**
   This function computes BIC for parent and children
 We use:
     cltrs -- parent cluster values
     hcltrs -- children values
     nearest_cdist -- data point-assigned cluster dist
     partition dist -- data point-partition dist
 */
void xmeans_coordinator::bic(split_score_t& score,
        std::unordered_map<unsigned, std::vector<unsigned>>& memb_cltrs) {

    // Compute for parent
    double pK = 1; // parent K
    double cK = 2; // children K
    double N = cluster_assignment_counts[score.lid]
                        + cluster_assignment_counts[score.rid];
    double psigma = 0;
    double csigma = 0;

    for (auto const& idx : memb_cltrs[score.lid]) {
            psigma += partition_dist[idx];
            csigma += nearest_cdist[idx];
    }

    for (auto const& idx : memb_cltrs[score.rid]) {
            psigma += partition_dist[idx];
            csigma += nearest_cdist[idx];
    }

    // Parent
    if (N - pK > 0) {
        psigma /= (double) (N - pK);
        double p = (pK - 1) + ncol * pK + 1;

        /* splitting criterion */
        double L = N * std::log(N) - N * std::log(N) - N *
            std::log(2.0 * PI) * .5 - N * ncol *
            std::log(psigma) * .5 - (N - pK) * .5;

        score.pscore = L - p * 0.5 * std::log(N);
    }

    // Children
    if (N - cK > 0) {
        csigma /= (double) (N - cK);
        double p = (cK - 1) + ncol * cK + 1;

        /* splitting criterion */
        double nl = cluster_assignment_counts[score.lid];
        double L = N * std::log(N) - nl * std::log(N) - N *
            std::log(2.0 * PI) * .5 - N * ncol *
            std::log(csigma) * .5 - (N - cK) * .5;

        score.cscore = L - p * 0.5 * std::log(N);

        double nr = cluster_assignment_counts[score.lid];
        L = N * std::log(N) - nr * std::log(N) - N *
            std::log(2.0 * PI) * .5- N * ncol *
            std::log(csigma) * .5 - (N - cK) * .5;
        score.cscore += L - p * .5 * std::log(N);
    }
}

void xmeans_coordinator::compute_bic_scores(
        std::vector<split_score_t>& bic_scores,
    std::unordered_map<unsigned, std::vector<unsigned>>& memb_cltrs) {

    // Creates structures to store bic scores & cluster membership
    auto itr = hcltrs.get_iterator();
    while (itr.has_next()) {
        auto kv = itr.next();
        assert(kv.first == kv.second->get_id());
#if 1
        printf("BIC evaluation for pid: %lu, lid: %u, rid: %u\n",
                kv.first, kv.second->get_zeroid(), kv.second->get_oneid());
#endif
        bic_scores.push_back(split_score_t(kv.second->get_id(),
                    kv.second->get_zeroid(), kv.second->get_oneid()));
    }

#if 0
    assert(std::accumulate(cluster_assignment_counts.begin(),
                cluster_assignment_counts.end(), 0)
                        == static_cast<llong_t>(nrow));
#endif

    // TODO: Slow
    // Creates structures to hold cluster membership
    accumulate(cluster_assignments, memb_cltrs);

    // Computes the bic scores for each parent, child combo
#pragma omp parallel for shared (bic_scores) schedule (dynamic)
    for (size_t idx = 0; idx < bic_scores.size(); idx++) {
        bic(bic_scores[idx], memb_cltrs);
    }
}

// NOTE: This modifies hcltrs
void xmeans_coordinator::partition_decision() {
    std::vector<split_score_t> bic_scores;
    std::unordered_map<unsigned, std::vector<unsigned>> memb_cltrs; // Parent
    compute_bic_scores(bic_scores, memb_cltrs);

    std::vector<bool> remove_cache;
    remove_cache.assign(bic_scores.size(), false);

#pragma omp parallel for shared (bic_scores)
    for (size_t i = 0; i < bic_scores.size(); i++) {
        auto score = bic_scores[i];
        if (score.pscore > score.cscore) {
#if 1
            printf("\nPart: %u will NOT split! pscore: %.4f > cscore: %.4f\n",
                    score.pid, score.pscore, score.cscore);
#endif
            // Move all in children clusters to (parent) partition
            auto const& lmembers = memb_cltrs[score.lid];
            for (size_t i = 0; i < memb_cltrs[score.lid].size(); i++)
               cluster_assignments[lmembers[i]] = score.pid;

            auto const& rmembers = memb_cltrs[score.lid];
            for (size_t i = 0; i < memb_cltrs[score.rid].size(); i++)
               cluster_assignments[rmembers[i]] = score.pid;

            // Deactivate both lid and rid
            deactivate(score.lid); deactivate(score.rid);

            // Deactivate pid
            deactivate(score.pid);
            remove_cache[i] = true;
            final_centroids[score.pid] = std::vector<double>(
                    cltrs->get_mean_rawptr(score.pid),
                    cltrs->get_mean_rawptr(score.pid) + ncol);
        } else {
#if 1
            printf("\nPart: %u will split! pscore: %.4f <= cscore: %.4f\n",
                    score.pid, score.pscore, score.cscore);
#endif
        }
    }

    for (size_t i = 0; i < remove_cache.size(); i++) {
        if (remove_cache[i])
            hcltrs.erase(bic_scores[i].pid);
    }
}

// Main driver
base::cluster_t xmeans_coordinator::run(
        double* allocd_data, const bool numa_opt) {
#ifdef PROFILER
    ProfilerStart("xmeans_coordinator.perf");
#endif

    build_thread_state();

    if (!numa_opt && NULL == allocd_data) {
        wake4run(ALLOC_DATA);
        wait4complete();
    } else if (allocd_data) { // No NUMA opt
        set_thread_data_ptr(allocd_data);
    }

    struct timeval start, end;
    gettimeofday(&start , NULL);

    if (_init_t == kbase::init_t::NONE)
        _init_t = kbase::init_t::FORGY;
    run_hinit(); // Initialize clusters

    // Run loop
    size_t iter = 0;

    unsigned curr_nclust = 2;
    while (true) {
        printf("Running a Partition Mean step...\n");
        // TODO: Do this simultaneously with H_EM step
        wake4run(MEAN);
        wait4complete();
        combine_partition_means();
        compute_pdist = true;

        for (iter = 0; iter < max_iters; iter++) {
            printf("\n\nNCLUST: %u, Iteration: %lu\n", curr_nclust, iter);
            // Now pick between the cluster splits
            wake4run(H_EM);
            wait4complete();
            update_clusters();
#if 1
            printf("\nAfter update_clusters ... Global hcltrs:\n");
            print_clusters();
            printf("\nAssignment counts:\n");
            base::sparse_print(cluster_assignment_counts);
            //printf("\nAssignments:\n");
            //base::print(cluster_assignments, nrow);
#endif
            printf("\n*****************************************************\n");
            if (compute_pdist)
                compute_pdist = false;
        }

        // Decide on split or not here
        partition_decision();

        if (curr_nclust >= k*2) {
            printf("\n\nCLUSTER SIZE EXIT @ %u!\n", curr_nclust);
            break;
        }

        // Update global state
        init_splits(); // Initialize possible splits

        // Break when clusters are inactive due to size
        if (hcltrs.keyless()) {
            assert(steady_state()); // NOTE: Comment when benchmarking
            printf("\n\nSTEADY STATE EXIT!\n");
            break;
        }
        curr_nclust = hcltrs.keycount()*2 + final_centroids.size();
    }
#ifdef PROFILER
    ProfilerStop();
#endif

    gettimeofday(&end, NULL);
#ifndef BIND
    printf("\n\nAlgorithmic time taken = %.6f sec\n",
        base::time_diff(start, end));
    printf("\n******************************************\n");
#endif

#ifndef BIND
    printf("Final cluster counts: \n");
    base::sparse_print(cluster_assignment_counts);
    printf("\n******************************************\n");
#endif

#if 0
    return base::cluster_t(this->nrow, this->ncol, iter, this->k,
            &cluster_assignments[0], &cluster_assignment_counts[0],
            hcltrs->get_means());
#else
    return base::cluster_t(); // TODO
#endif
}
}
<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	connectionitf.cxx
 *
 *   DESCRIPTION
 *      implementation of the pqxx::ConnectionItf abstract base class.
 *   pqxx::ConnectionItf encapsulates a frontend to backend connection
 *
 * Copyright (c) 2001-2003, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 *-------------------------------------------------------------------------
 */
#include <algorithm>
#include <cstdio>
#include <stdexcept>

#include "pqxx/connectionitf.h"
#include "pqxx/result.h"
#include "pqxx/transaction.h"
#include "pqxx/trigger.h"

using namespace PGSTD;

namespace
{

// Keep track of a pointer to be free()d automatically.
// Ownership policy is simple: object dies when PQAlloc object's value does.
template<typename T> class PQAlloc
{
  T *m_Obj;
public:
  PQAlloc() : m_Obj(0) {}
  explicit PQAlloc(T *obj) : m_Obj(obj) {}
  ~PQAlloc() { close(); }

  PQAlloc &operator=(T *obj) throw ()
  {
    if (obj != m_Obj)
    {
      close();
      m_Obj = obj;
    }
    return *this;
  }

  operator bool() const throw () { return m_Obj != 0; }
  bool operator!() const throw () { return !m_Obj; }

  T *operator->() const
  {
    if (!m_Obj) throw logic_error("Null pointer dereferenced");
    return m_Obj;
  }

  T &operator*() const { return *operator->(); }

  T *c_ptr() const throw () { return m_Obj; }

  void close() throw () { if (m_Obj) freemem(); m_Obj = 0; }

  void freemem() throw ()
  {
#ifdef HAVE_PQFREEMEM
    PQfreemem(m_Obj);
#else
    free(m_Obj);
#endif
  }

private:
  PQAlloc(const PQAlloc &);		// Not allowed
  PQAlloc &operator=(const PQAlloc &);	// Not allowed
};
}

extern "C"
{
// Pass C-linkage notice processor call on to C++-linkage Noticer object.  The
// void * argument points to the Noticer.
void pqxxNoticeCaller(void *arg, const char *Msg)
{
  if (arg && Msg) (*static_cast<pqxx::Noticer *>(arg))(Msg);
}
}

pqxx::ConnectionItf::ConnectionItf(const string &ConnInfo) :
  m_ConnInfo(ConnInfo),
  m_Conn(0),
  m_Trans(),
  m_Noticer(),
  m_Trace(0)
{
}

pqxx::ConnectionItf::ConnectionItf(const char ConnInfo[]) :
  m_ConnInfo(ConnInfo ? ConnInfo : ""),
  m_Conn(0),
  m_Trans(),
  m_Noticer(),
  m_Trace(0)
{
}

void pqxx::ConnectionItf::Connect() const
{
  if (m_Conn) throw logic_error("libqxx internal error: spurious Connect()");

  m_Conn = PQconnectdb(m_ConnInfo.c_str());

  if (!m_Conn)
    throw broken_connection();

  if (!is_open())
  {
    const string Msg( ErrMsg() );
    Disconnect();
    throw broken_connection(Msg);
  }

  if (Status() != CONNECTION_OK)
  {
    const string Msg( ErrMsg() );
    Disconnect();
    throw runtime_error(Msg);
  }

  SetupState();
}

void pqxx::ConnectionItf::Deactivate() const
{
  if (m_Conn)
  {
    if (m_Trans.get())
      throw logic_error("Attempt to deactivate connection while transaction "
	                "'" + m_Trans.get()->Name() + "' "
			"still open");

    Disconnect();
  }
}

void pqxx::ConnectionItf::SetClientEncoding(const char Encoding[])
{
  if (PQsetClientEncoding(m_Conn, Encoding) != 0)
    throw runtime_error("Could not set client encoding to " +
	                string(Encoding));
}

/** Set up various parts of logical connection state that may need to be
 * recovered because the physical connection to the database was lost and is
 * being reset, or that may not have been initialized yet.
 */
void pqxx::ConnectionItf::SetupState() const
{
  if (!m_Conn)
    throw logic_error("libpqxx internal error: SetupState() on no connection");

  if (m_Noticer.get())
    PQsetNoticeProcessor(m_Conn, pqxxNoticeCaller, m_Noticer.get());

  InternalSetTrace();

  // Reinstate all active triggers
  if (!m_Triggers.empty())
  {
    const TriggerList::const_iterator End = m_Triggers.end();
    string Last;
    for (TriggerList::const_iterator i = m_Triggers.begin(); i != End; ++i)
    {
      // m_Triggers can handle multiple Triggers waiting on the same event;
      // issue just one LISTEN for each event.
      if (i->first != Last)
      {
        Result R( PQexec(m_Conn, ("LISTEN " + i->first).c_str()) );
        R.CheckStatus();
        Last = i->first;
      }
    }
  }
}

void pqxx::ConnectionItf::Disconnect() const throw ()
{
  if (m_Conn)
  {
    PQfinish(m_Conn);
    m_Conn = 0;
  }
}

bool pqxx::ConnectionItf::is_open() const
{
  return m_Conn && (Status() != CONNECTION_BAD);
}

auto_ptr<pqxx::Noticer>
pqxx::ConnectionItf::SetNoticer(auto_ptr<pqxx::Noticer> N)
{
  if (N.get()) PQsetNoticeProcessor(m_Conn, pqxxNoticeCaller, N.get());
  else PQsetNoticeProcessor(m_Conn, 0, 0);

  auto_ptr<Noticer> Old = m_Noticer;
  // TODO: Can this line fail?  If yes, we'd be killing Old prematurely...
  m_Noticer = N;

  return Old;
}

void pqxx::ConnectionItf::ProcessNotice(const char msg[]) throw ()
{
  if (msg)
  {
    // TODO: Find cleaner solution for default case!
    if (m_Noticer.get()) (*m_Noticer.get())(msg);
    else fputs(msg, stderr);
  }
}

void pqxx::ConnectionItf::Trace(FILE *Out)
{
  m_Trace = Out;
  if (m_Conn) InternalSetTrace();
}

void pqxx::ConnectionItf::AddTrigger(pqxx::Trigger *T)
{
  if (!T) throw invalid_argument("Null trigger registered");

  // Add to triggers list and attempt to start listening.
  const TriggerList::iterator p = m_Triggers.find(T->Name());
  const TriggerList::value_type NewVal(T->Name(), T);

  if (m_Conn && (p == m_Triggers.end()))
  {
    // Not listening on this event yet, start doing so.
    //
    Result R( PQexec(m_Conn, ("LISTEN " + string(T->Name())).c_str()) );

    try
    {
      R.CheckStatus();
    }
    catch (const broken_connection &)
    {
    }
    catch (const exception &)
    {
      if (is_open()) throw;
    }
    m_Triggers.insert(NewVal);
  }
  else
  {
    m_Triggers.insert(p, NewVal);
  }

}

void pqxx::ConnectionItf::RemoveTrigger(pqxx::Trigger *T) throw ()
{
  if (!T) return;

  try
  {
    // Keep Sun compiler happy...  Hope it doesn't annoy other compilers
    pair<const string, Trigger *> tmp_pair(T->Name(), T);
    TriggerList::value_type E = tmp_pair;

    typedef pair<TriggerList::iterator, TriggerList::iterator> Range;
    Range R = m_Triggers.equal_range(E.first);

    const TriggerList::iterator i = find(R.first, R.second, E);

    if (i == R.second)
    {
      ProcessNotice("Attempt to remove unknown trigger '" +
		    E.first +
		    "'");
    }
    else
    {
      if (m_Conn && (R.second == ++R.first))
	PQexec(m_Conn, ("UNLISTEN " + string(T->Name())).c_str());

      m_Triggers.erase(i);
    }
  }
  catch (const exception &e)
  {
    ProcessNotice(e.what());
  }
}

void pqxx::ConnectionItf::GetNotifs()
{
  if (!m_Conn) return;

  PQconsumeInput(m_Conn);

  // Even if somehow we receive notifications during our transaction, don't
  // deliver them.
  if (m_Trans.get()) return;

  for (PQAlloc<PGnotify> N( PQnotifies(m_Conn) ); N; N = PQnotifies(m_Conn))
  {
    typedef TriggerList::iterator TI;

    pair<TI, TI> Hit = m_Triggers.equal_range(string(N->relname));
    for (TI i = Hit.first; i != Hit.second; ++i)
      try
      {
        (*i->second)(N->be_pid);
      }
      catch (const exception &e)
      {
	ProcessNotice("Exception in trigger handler '" +
		      i->first +
		      "': " +
		      e.what() +
		      "\n");
      }

    N.close();
  }
}

const char *pqxx::ConnectionItf::ErrMsg() const
{
  return m_Conn ? PQerrorMessage(m_Conn) : "No connection to database";
}

pqxx::Result pqxx::ConnectionItf::Exec(const char Query[],
                                       int Retries,
				       const char OnReconnect[])
{
  Activate();

  Result R( PQexec(m_Conn, Query) );

  while ((Retries > 0) && !R && !is_open())
  {
    Retries--;

    Reset(OnReconnect);
    if (is_open()) R = PQexec(m_Conn, Query);
  }

  if (!R) throw broken_connection();
  R.CheckStatus();

  GetNotifs();

  return R;
}

void pqxx::ConnectionItf::Reset(const char OnReconnect[])
{
  // Attempt to set up or restore connection
  if (!m_Conn) Connect();
  else
  {
    PQreset(m_Conn);
    SetupState();

    // Perform any extra patchup work involved in restoring the connection,
    // typically set up a transaction.
    if (OnReconnect)
    {
      Result Temp( PQexec(m_Conn, OnReconnect) );
      Temp.CheckStatus();
    }
  }
}

void pqxx::ConnectionItf::close() throw ()
{
  try
  {
    if (m_Trans.get())
      ProcessNotice("Closing connection while transaction '" +
		    m_Trans.get()->Name() +
		    "' still open\n");

    if (!m_Triggers.empty())
    {
      string T;
      for (TriggerList::const_iterator i = m_Triggers.begin();
	   i != m_Triggers.end();
	   ++i)
	T += " " + i->first;

        ProcessNotice("Closing connection with outstanding triggers:" +
	              T +
		      "\n");
      m_Triggers.clear();
    }

    Disconnect();
  }
  catch (...)
  {
  }
}

void pqxx::ConnectionItf::InternalSetTrace() const
{
  if (m_Trace) PQtrace(m_Conn, m_Trace);
  else PQuntrace(m_Conn);
}

void pqxx::ConnectionItf::RegisterTransaction(const TransactionItf *T)
{
  m_Trans.Register(T);
}

void pqxx::ConnectionItf::UnregisterTransaction(const TransactionItf *T) throw ()
{
  try
  {
    m_Trans.Unregister(T);
  }
  catch (const exception &e)
  {
    ProcessNotice(string(e.what()) + "\n");
  }
}

void pqxx::ConnectionItf::MakeEmpty(pqxx::Result &R, ExecStatusType Stat)
{
  if (!m_Conn)
    throw logic_error("Internal libpqxx error: MakeEmpty() on null connection");

  R = Result(PQmakeEmptyPGresult(m_Conn, Stat));
}

void pqxx::ConnectionItf::BeginCopyRead(const string &Table)
{
  Result R( Exec(("COPY " + Table + " TO STDOUT").c_str()) );
  R.CheckStatus();
}

bool pqxx::ConnectionItf::ReadCopyLine(string &Line)
{
  if (!m_Conn)
    throw logic_error("Internal libpqxx error: "
	              "ReadCopyLine() on null connection");

  char Buf[256];
  bool LineComplete = false;

  Line.erase();

  while (!LineComplete)
  {
    switch (PQgetline(m_Conn, Buf, sizeof(Buf)))
    {
    case EOF:
      throw runtime_error("Unexpected EOF from backend");

    case 0:
      LineComplete = true;
      break;

    case 1:
      break;

    default:
      throw runtime_error("Unexpected COPY response from backend");
    }

    Line += Buf;
  }

  bool Result = (Line != "\\.");

  if (!Result) Line.erase();

  return Result;
}

void pqxx::ConnectionItf::BeginCopyWrite(const string &Table)
{
  Result R( Exec(("COPY " + Table + " FROM STDIN").c_str()) );
  R.CheckStatus();
}

void pqxx::ConnectionItf::WriteCopyLine(const string &Line)
{
  if (!m_Conn)
    throw logic_error("Internal libpqxx error: "
	              "WriteCopyLine() on null connection");

  PQputline(m_Conn, (Line + "\n").c_str());
}

// End COPY operation.  Careful: this assumes that no more lines remain to be
// read or written, and the COPY operation has been properly terminated with a
// line containing only the two characters "\."
void pqxx::ConnectionItf::EndCopy()
{
  if (PQendcopy(m_Conn) != 0) throw runtime_error(ErrMsg());
}

<commit_msg>Made less confusing to doxygen<commit_after>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	connectionitf.cxx
 *
 *   DESCRIPTION
 *      implementation of the pqxx::ConnectionItf abstract base class.
 *   pqxx::ConnectionItf encapsulates a frontend to backend connection
 *
 * Copyright (c) 2001-2003, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 *-------------------------------------------------------------------------
 */
#include <algorithm>
#include <cstdio>
#include <stdexcept>

#include "pqxx/connectionitf.h"
#include "pqxx/result.h"
#include "pqxx/transaction.h"
#include "pqxx/trigger.h"

using namespace PGSTD;

namespace
{

// Keep track of a pointer to be free()d automatically.
// Ownership policy is simple: object dies when PQAlloc object's value does.
template<typename T> class PQAlloc
{
  T *m_Obj;
public:
  PQAlloc() : m_Obj(0) {}
  explicit PQAlloc(T *obj) : m_Obj(obj) {}
  ~PQAlloc() { close(); }

  PQAlloc &operator=(T *obj) throw ()
  {
    if (obj != m_Obj)
    {
      close();
      m_Obj = obj;
    }
    return *this;
  }

  operator bool() const throw () { return m_Obj != 0; }
  bool operator!() const throw () { return !m_Obj; }

  T *operator->() const
  {
    if (!m_Obj) throw logic_error("Null pointer dereferenced");
    return m_Obj;
  }

  T &operator*() const { return *operator->(); }

  T *c_ptr() const throw () { return m_Obj; }

  void close() throw () { if (m_Obj) freemem(); m_Obj = 0; }

  void freemem() throw ()
  {
#ifdef HAVE_PQFREEMEM
    PQfreemem(m_Obj);
#else
    free(m_Obj);
#endif
  }

private:
  PQAlloc(const PQAlloc &);		// Not allowed
  PQAlloc &operator=(const PQAlloc &);	// Not allowed
};
}

extern "C"
{
// Pass C-linkage notice processor call on to C++-linkage Noticer object.  The
// void * argument points to the Noticer.
void pqxxNoticeCaller(void *arg, const char *Msg)
{
  if (arg && Msg) (*static_cast<pqxx::Noticer *>(arg))(Msg);
}
}

pqxx::ConnectionItf::ConnectionItf(const string &ConnInfo) :
  m_ConnInfo(ConnInfo),
  m_Conn(0),
  m_Trans(),
  m_Noticer(),
  m_Trace(0)
{
}

pqxx::ConnectionItf::ConnectionItf(const char ConnInfo[]) :
  m_ConnInfo(ConnInfo ? ConnInfo : ""),
  m_Conn(0),
  m_Trans(),
  m_Noticer(),
  m_Trace(0)
{
}

void pqxx::ConnectionItf::Connect() const
{
  if (m_Conn) throw logic_error("libqxx internal error: spurious Connect()");

  m_Conn = PQconnectdb(m_ConnInfo.c_str());

  if (!m_Conn)
    throw broken_connection();

  if (!is_open())
  {
    const string Msg( ErrMsg() );
    Disconnect();
    throw broken_connection(Msg);
  }

  if (Status() != CONNECTION_OK)
  {
    const string Msg( ErrMsg() );
    Disconnect();
    throw runtime_error(Msg);
  }

  SetupState();
}

void pqxx::ConnectionItf::Deactivate() const
{
  if (m_Conn)
  {
    if (m_Trans.get())
      throw logic_error("Attempt to deactivate connection while transaction "
	                "'" + m_Trans.get()->Name() + "' "
			"still open");

    Disconnect();
  }
}

void pqxx::ConnectionItf::SetClientEncoding(const char Encoding[])
{
  if (PQsetClientEncoding(m_Conn, Encoding) != 0)
    throw runtime_error("Could not set client encoding to " +
	                string(Encoding));
}

/** Set up various parts of logical connection state that may need to be
 * recovered because the physical connection to the database was lost and is
 * being reset, or that may not have been initialized yet.
 */
void pqxx::ConnectionItf::SetupState() const
{
  if (!m_Conn)
    throw logic_error("libpqxx internal error: SetupState() on no connection");

  if (m_Noticer.get())
    PQsetNoticeProcessor(m_Conn, pqxxNoticeCaller, m_Noticer.get());

  InternalSetTrace();

  // Reinstate all active triggers
  if (!m_Triggers.empty())
  {
    const TriggerList::const_iterator End = m_Triggers.end();
    string Last;
    for (TriggerList::const_iterator i = m_Triggers.begin(); i != End; ++i)
    {
      // m_Triggers can handle multiple Triggers waiting on the same event;
      // issue just one LISTEN for each event.
      if (i->first != Last)
      {
        Result R( PQexec(m_Conn, ("LISTEN " + i->first).c_str()) );
        R.CheckStatus();
        Last = i->first;
      }
    }
  }
}

void pqxx::ConnectionItf::Disconnect() const throw ()
{
  if (m_Conn)
  {
    PQfinish(m_Conn);
    m_Conn = 0;
  }
}

bool pqxx::ConnectionItf::is_open() const
{
  return m_Conn && (Status() != CONNECTION_BAD);
}

auto_ptr<Noticer>
pqxx::ConnectionItf::SetNoticer(auto_ptr<Noticer> N)
{
  if (N.get()) PQsetNoticeProcessor(m_Conn, pqxxNoticeCaller, N.get());
  else PQsetNoticeProcessor(m_Conn, 0, 0);

  auto_ptr<Noticer> Old = m_Noticer;
  // TODO: Can this line fail?  If yes, we'd be killing Old prematurely...
  m_Noticer = N;

  return Old;
}

void pqxx::ConnectionItf::ProcessNotice(const char msg[]) throw ()
{
  if (msg)
  {
    // TODO: Find cleaner solution for default case!
    if (m_Noticer.get()) (*m_Noticer.get())(msg);
    else fputs(msg, stderr);
  }
}

void pqxx::ConnectionItf::Trace(FILE *Out)
{
  m_Trace = Out;
  if (m_Conn) InternalSetTrace();
}

void pqxx::ConnectionItf::AddTrigger(pqxx::Trigger *T)
{
  if (!T) throw invalid_argument("Null trigger registered");

  // Add to triggers list and attempt to start listening.
  const TriggerList::iterator p = m_Triggers.find(T->Name());
  const TriggerList::value_type NewVal(T->Name(), T);

  if (m_Conn && (p == m_Triggers.end()))
  {
    // Not listening on this event yet, start doing so.
    //
    Result R( PQexec(m_Conn, ("LISTEN " + string(T->Name())).c_str()) );

    try
    {
      R.CheckStatus();
    }
    catch (const broken_connection &)
    {
    }
    catch (const exception &)
    {
      if (is_open()) throw;
    }
    m_Triggers.insert(NewVal);
  }
  else
  {
    m_Triggers.insert(p, NewVal);
  }

}

void pqxx::ConnectionItf::RemoveTrigger(pqxx::Trigger *T) throw ()
{
  if (!T) return;

  try
  {
    // Keep Sun compiler happy...  Hope it doesn't annoy other compilers
    pair<const string, Trigger *> tmp_pair(T->Name(), T);
    TriggerList::value_type E = tmp_pair;

    typedef pair<TriggerList::iterator, TriggerList::iterator> Range;
    Range R = m_Triggers.equal_range(E.first);

    const TriggerList::iterator i = find(R.first, R.second, E);

    if (i == R.second)
    {
      ProcessNotice("Attempt to remove unknown trigger '" +
		    E.first +
		    "'");
    }
    else
    {
      if (m_Conn && (R.second == ++R.first))
	PQexec(m_Conn, ("UNLISTEN " + string(T->Name())).c_str());

      m_Triggers.erase(i);
    }
  }
  catch (const exception &e)
  {
    ProcessNotice(e.what());
  }
}

void pqxx::ConnectionItf::GetNotifs()
{
  if (!m_Conn) return;

  PQconsumeInput(m_Conn);

  // Even if somehow we receive notifications during our transaction, don't
  // deliver them.
  if (m_Trans.get()) return;

  for (PQAlloc<PGnotify> N( PQnotifies(m_Conn) ); N; N = PQnotifies(m_Conn))
  {
    typedef TriggerList::iterator TI;

    pair<TI, TI> Hit = m_Triggers.equal_range(string(N->relname));
    for (TI i = Hit.first; i != Hit.second; ++i)
      try
      {
        (*i->second)(N->be_pid);
      }
      catch (const exception &e)
      {
	ProcessNotice("Exception in trigger handler '" +
		      i->first +
		      "': " +
		      e.what() +
		      "\n");
      }

    N.close();
  }
}

const char *pqxx::ConnectionItf::ErrMsg() const
{
  return m_Conn ? PQerrorMessage(m_Conn) : "No connection to database";
}

pqxx::Result pqxx::ConnectionItf::Exec(const char Query[],
                                       int Retries,
				       const char OnReconnect[])
{
  Activate();

  Result R( PQexec(m_Conn, Query) );

  while ((Retries > 0) && !R && !is_open())
  {
    Retries--;

    Reset(OnReconnect);
    if (is_open()) R = PQexec(m_Conn, Query);
  }

  if (!R) throw broken_connection();
  R.CheckStatus();

  GetNotifs();

  return R;
}

void pqxx::ConnectionItf::Reset(const char OnReconnect[])
{
  // Attempt to set up or restore connection
  if (!m_Conn) Connect();
  else
  {
    PQreset(m_Conn);
    SetupState();

    // Perform any extra patchup work involved in restoring the connection,
    // typically set up a transaction.
    if (OnReconnect)
    {
      Result Temp( PQexec(m_Conn, OnReconnect) );
      Temp.CheckStatus();
    }
  }
}

void pqxx::ConnectionItf::close() throw ()
{
  try
  {
    if (m_Trans.get())
      ProcessNotice("Closing connection while transaction '" +
		    m_Trans.get()->Name() +
		    "' still open\n");

    if (!m_Triggers.empty())
    {
      string T;
      for (TriggerList::const_iterator i = m_Triggers.begin();
	   i != m_Triggers.end();
	   ++i)
	T += " " + i->first;

        ProcessNotice("Closing connection with outstanding triggers:" +
	              T +
		      "\n");
      m_Triggers.clear();
    }

    Disconnect();
  }
  catch (...)
  {
  }
}

void pqxx::ConnectionItf::InternalSetTrace() const
{
  if (m_Trace) PQtrace(m_Conn, m_Trace);
  else PQuntrace(m_Conn);
}

void pqxx::ConnectionItf::RegisterTransaction(const TransactionItf *T)
{
  m_Trans.Register(T);
}

void pqxx::ConnectionItf::UnregisterTransaction(const TransactionItf *T) throw ()
{
  try
  {
    m_Trans.Unregister(T);
  }
  catch (const exception &e)
  {
    ProcessNotice(string(e.what()) + "\n");
  }
}

void pqxx::ConnectionItf::MakeEmpty(pqxx::Result &R, ExecStatusType Stat)
{
  if (!m_Conn)
    throw logic_error("Internal libpqxx error: MakeEmpty() on null connection");

  R = Result(PQmakeEmptyPGresult(m_Conn, Stat));
}

void pqxx::ConnectionItf::BeginCopyRead(const string &Table)
{
  Result R( Exec(("COPY " + Table + " TO STDOUT").c_str()) );
  R.CheckStatus();
}

bool pqxx::ConnectionItf::ReadCopyLine(string &Line)
{
  if (!m_Conn)
    throw logic_error("Internal libpqxx error: "
	              "ReadCopyLine() on null connection");

  char Buf[256];
  bool LineComplete = false;

  Line.erase();

  while (!LineComplete)
  {
    switch (PQgetline(m_Conn, Buf, sizeof(Buf)))
    {
    case EOF:
      throw runtime_error("Unexpected EOF from backend");

    case 0:
      LineComplete = true;
      break;

    case 1:
      break;

    default:
      throw runtime_error("Unexpected COPY response from backend");
    }

    Line += Buf;
  }

  bool Result = (Line != "\\.");

  if (!Result) Line.erase();

  return Result;
}

void pqxx::ConnectionItf::BeginCopyWrite(const string &Table)
{
  Result R( Exec(("COPY " + Table + " FROM STDIN").c_str()) );
  R.CheckStatus();
}

void pqxx::ConnectionItf::WriteCopyLine(const string &Line)
{
  if (!m_Conn)
    throw logic_error("Internal libpqxx error: "
	              "WriteCopyLine() on null connection");

  PQputline(m_Conn, (Line + "\n").c_str());
}

// End COPY operation.  Careful: this assumes that no more lines remain to be
// read or written, and the COPY operation has been properly terminated with a
// line containing only the two characters "\."
void pqxx::ConnectionItf::EndCopy()
{
  if (PQendcopy(m_Conn) != 0) throw runtime_error(ErrMsg());
}

<|endoftext|>


<commit_before>#include "w5100.h"
#include "socket.h"
extern "C" {
#include "string.h"
}

#include "WProgram.h"

#include "ethernet.h"
#include "client.h"
#include "server.h"

uint16_t Client::_srcport = 1024;

Client::Client() : _connected(false) {
}

Client::Client(uint8_t sock) : _connected(true), _sock(sock) {
}

Client::Client(uint8_t *ip, uint16_t port) : _ip(ip), _port(port), _connected(false) {
}

uint8_t Client::connect() {
  if (_connected)
    return 0;

  int i;
  for (i=0; i<MAX_SOCK_NUM; i++) {
    uint8_t s = W5100.readSnSR(i);
    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) {
      _sock = i;
      break;
    }
  }

  if (i == MAX_SOCK_NUM)
    return 0;

  _srcport++;
  if (_srcport == 0) _srcport = 1024;
  socket(_sock, SnMR::TCP, _srcport, 0);

  if (!::connect(_sock, _ip, _port))
    return 0;

  while (status() != SnSR::ESTABLISHED) {
    delay(1);
    if (status() == SnSR::CLOSED)
      return 0;
  }

  _connected = true;
  return 1;
}

void Client::write(uint8_t b) {
  if (_connected)
    send(_sock, &b, 1);
}

void Client::write(const char *str) {
  if (_connected)
    send(_sock, (const uint8_t *)str, strlen(str));
}

void Client::write(const uint8_t *buf, size_t size) {
  if (_connected)
    send(_sock, buf, size);
}

int Client::available() {
  if (_connected)
    return W5100.getRXReceivedSize(_sock);
  return 0;
}

int Client::read() {
  uint8_t b;
  if (!available())
    return -1;
  recv(_sock, &b, 1);
  return b;
}

void Client::flush() {
  while (available())
    read();
}

void Client::stop() {
  if (!_connected)
    return;

  // attempt to close the connection gracefully (send a FIN to other side)
  disconnect(_sock);
  unsigned long start = millis();

  // wait a second for the connection to close
  while (status() != SnSR::CLOSED && millis() - start < 1000)
    delay(1);

  // if it hasn't closed, close it forcefully
  if (status() != SnSR::CLOSED)
    close(_sock);

  EthernetClass::_server_port[_sock] = 0;
  _connected = false;
}

uint8_t Client::connected() {
  uint8_t s = status();
  return !(s == SnSR::LISTEN || s == SnSR::CLOSED || s == SnSR::FIN_WAIT ||
    (s == SnSR::CLOSE_WAIT && !available()));
}

uint8_t Client::status() {
  return W5100.readSnSR(_sock);
}

// the next three functions are a hack so we can compare the client returned
// by Server::available() to null, or use it as the condition in an
// if-statement.  this lets us stay compatible with the Processing network
// library.

uint8_t Client::operator==(int p) {
  return !_connected;
}

uint8_t Client::operator!=(int p) {
  return _connected;
}

Client::operator bool() {
  return _connected;
}
<commit_msg>Return sensible values from Client::connected() and Client::status() if we know it's not connected.<commit_after>#include "w5100.h"
#include "socket.h"
extern "C" {
#include "string.h"
}

#include "WProgram.h"

#include "ethernet.h"
#include "client.h"
#include "server.h"

uint16_t Client::_srcport = 1024;

Client::Client() : _connected(false) {
}

Client::Client(uint8_t sock) : _connected(true), _sock(sock) {
}

Client::Client(uint8_t *ip, uint16_t port) : _ip(ip), _port(port), _connected(false) {
}

uint8_t Client::connect() {
  if (_connected)
    return 0;

  int i;
  for (i=0; i<MAX_SOCK_NUM; i++) {
    uint8_t s = W5100.readSnSR(i);
    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) {
      _sock = i;
      break;
    }
  }

  if (i == MAX_SOCK_NUM)
    return 0;

  _srcport++;
  if (_srcport == 0) _srcport = 1024;
  socket(_sock, SnMR::TCP, _srcport, 0);

  if (!::connect(_sock, _ip, _port))
    return 0;

  while (status() != SnSR::ESTABLISHED) {
    delay(1);
    if (status() == SnSR::CLOSED)
      return 0;
  }

  _connected = true;
  return 1;
}

void Client::write(uint8_t b) {
  if (_connected)
    send(_sock, &b, 1);
}

void Client::write(const char *str) {
  if (_connected)
    send(_sock, (const uint8_t *)str, strlen(str));
}

void Client::write(const uint8_t *buf, size_t size) {
  if (_connected)
    send(_sock, buf, size);
}

int Client::available() {
  if (_connected)
    return W5100.getRXReceivedSize(_sock);
  return 0;
}

int Client::read() {
  uint8_t b;
  if (!available())
    return -1;
  recv(_sock, &b, 1);
  return b;
}

void Client::flush() {
  while (available())
    read();
}

void Client::stop() {
  if (!_connected)
    return;

  // attempt to close the connection gracefully (send a FIN to other side)
  disconnect(_sock);
  unsigned long start = millis();

  // wait a second for the connection to close
  while (status() != SnSR::CLOSED && millis() - start < 1000)
    delay(1);

  // if it hasn't closed, close it forcefully
  if (status() != SnSR::CLOSED)
    close(_sock);

  EthernetClass::_server_port[_sock] = 0;
  _connected = false;
}

uint8_t Client::connected() {
  if (!_connected) return 0;

  uint8_t s = status();
  return !(s == SnSR::LISTEN || s == SnSR::CLOSED || s == SnSR::FIN_WAIT ||
    (s == SnSR::CLOSE_WAIT && !available()));
}

uint8_t Client::status() {
  if (!_connected) return SnSR::CLOSED;
  return W5100.readSnSR(_sock);
}

// the next three functions are a hack so we can compare the client returned
// by Server::available() to null, or use it as the condition in an
// if-statement.  this lets us stay compatible with the Processing network
// library.

uint8_t Client::operator==(int p) {
  return !_connected;
}

uint8_t Client::operator!=(int p) {
  return _connected;
}

Client::operator bool() {
  return _connected;
}
<|endoftext|>


<commit_before>#include "acsetup.hpp"
#include "details/compound_listener.hpp"

#include <cassert>
#include <algorithm>
#include <exception>
#include <boost/ref.hpp>
#include <boost/bind.hpp>
#include <boost/current_function.hpp>

#include "xiva/logger.hpp"

namespace xiva { namespace details {

compound_listener::compound_listener() {
}

compound_listener::~compound_listener() {
}

void
compound_listener::connection_opened(std::string const &to, globals::connection_id id) throw (std::exception) {
	notify_connection_opened(to, id);
}

void
compound_listener::connection_closed(std::string const &to, globals::connection_id id) throw (std::exception) {
	notify_connection_closed(to, id);
}

void
compound_listener::disconnected(std::string const &to) throw (std::exception) {
	notify_disconnected(to);
}

void
compound_listener::init(settings const &s) {
	(void) s;
}

void
compound_listener::attach_logger(boost::intrusive_ptr<logger> const &log) {
	assert(log);
	logger_ = log;
}

void
compound_listener::add_connection_listener(listener_ptr_type const &l) {
	assert(l);
	listeners_.push_back(l);
}

bool
compound_listener::empty() const {
	return listeners_.empty();
}

boost::intrusive_ptr<logger> const&
compound_listener::log() const {
	return logger_;
}

void
compound_listener::notify_connection_opened(std::string const &to, globals::connection_id id) {
	try {
		std::for_each(listeners_.begin(), listeners_.end(),
		    boost::bind(&connection_listener::connection_opened, _1, boost::cref(to), id));
	}
	catch (std::exception const &e) {
		logger_->error("exception caught in %s: %s", BOOST_CURRENT_FUNCTION, e.what());
		throw;
	}
}

void
compound_listener::notify_connection_closed(std::string const &to, globals::connection_id id) {
	try {
		std::for_each(listeners_.begin(), listeners_.end(),
		    boost::bind(&connection_listener::connection_closed, _1, boost::cref(to), id));
	}
	catch (std::exception const &e) {
		logger_->error("exception caught in %s: %s", BOOST_CURRENT_FUNCTION, e.what());
		throw;
	}
}

void
compound_listener::notify_disconnected(std::string const &to) {
	try {
		std::for_each(listeners_.begin(), listeners_.end(),
		    boost::bind(&connection_listener::disconnected, _1, boost::cref(to)));
	}
	catch (std::exception const &e) {
		logger_->error("exception caught in %s: %s", BOOST_CURRENT_FUNCTION, e.what());
		throw;
	}
}

}} // namespaces
<commit_msg>do rollback connection_closed if notify_connection_opened failed<commit_after>#include "acsetup.hpp"
#include "details/compound_listener.hpp"

#include <cassert>
#include <algorithm>
#include <exception>
#include <boost/ref.hpp>
#include <boost/bind.hpp>
#include <boost/current_function.hpp>

#include "xiva/logger.hpp"

namespace xiva { namespace details {

compound_listener::compound_listener() {
}

compound_listener::~compound_listener() {
}

void
compound_listener::connection_opened(std::string const &to, globals::connection_id id) throw (std::exception) {
	notify_connection_opened(to, id);
}

void
compound_listener::connection_closed(std::string const &to, globals::connection_id id) throw (std::exception) {
	notify_connection_closed(to, id);
}

void
compound_listener::disconnected(std::string const &to) throw (std::exception) {
	notify_disconnected(to);
}

void
compound_listener::init(settings const &s) {
	(void) s;
}

void
compound_listener::attach_logger(boost::intrusive_ptr<logger> const &log) {
	assert(log);
	logger_ = log;
}

void
compound_listener::add_connection_listener(listener_ptr_type const &l) {
	assert(l);
	listeners_.push_back(l);
}

bool
compound_listener::empty() const {
	return listeners_.empty();
}

boost::intrusive_ptr<logger> const&
compound_listener::log() const {
	return logger_;
}

void
compound_listener::notify_connection_opened(std::string const &to, globals::connection_id id) {

	std::list<listener_ptr_type>::iterator it = listeners_.begin(), end = listeners_.end();
	try {
		//std::for_each(listeners_.begin(), listeners_.end(),
		//	boost::bind(&connection_listener::connection_opened, _1, boost::cref(to), id));
		while(it != end) {
			(*it)->connection_opened(to, id);
			++it;
		}
	}
	catch (std::exception const &e) {
		logger_->error("exception caught in %s: %s", BOOST_CURRENT_FUNCTION, e.what());
		while(it != listeners_.begin()) {
			--it;
			(*it)->connection_closed(to, id);
		}
		throw;
	}
}

void
compound_listener::notify_connection_closed(std::string const &to, globals::connection_id id) {
	try {
		std::for_each(listeners_.begin(), listeners_.end(),
			boost::bind(&connection_listener::connection_closed, _1, boost::cref(to), id));
	}
	catch (std::exception const &e) {
		logger_->error("exception caught in %s: %s", BOOST_CURRENT_FUNCTION, e.what());
		throw;
	}
}

void
compound_listener::notify_disconnected(std::string const &to) {
	try {
		std::for_each(listeners_.begin(), listeners_.end(),
			boost::bind(&connection_listener::disconnected, _1, boost::cref(to)));
	}
	catch (std::exception const &e) {
		logger_->error("exception caught in %s: %s", BOOST_CURRENT_FUNCTION, e.what());
		throw;
	}
}

}} // namespaces
<|endoftext|>


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

#ifndef LIBQ_TIME_SET_HPP
#define LIBQ_TIME_SET_HPP

#include <q/timer.hpp>

#include <map>

namespace q {

namespace detail {

template< typename T >
struct default_construction
{
	typedef T type;

	static type empty( )
	{
		return T( );
	}

	static type value( const T& t )
	{
		return t;
	}

	static type value( T&& t )
	{
		return type( std::move( t ) );
	}
};

template< typename T >
struct time_set_less_than
{
	typedef std::tuple< timer::point_type, T > element_type;

	constexpr bool operator( )(
		const element_type& a, const element_type& b ) const
	{
		return std::get< 0 >( a ) < std::get< 0 >( b );
	}
};

} // namespace detail

/**
 * The time_set class combines time and data of type T, ordered by time.
 *
 * This is useful to order data by time, and quickly be able to find the
 * closest data by time, as well as to find how long until the next time
 * (closest to now).
 */
template<
	typename T,
	typename LessThan = detail::time_set_less_than< T >,
	typename IfEmpty = detail::default_construction< T >
>
class time_set
{
public:
	typedef std::pair< timer::point_type, T > element_type;
	typedef std::is_same< IfEmpty, detail::default_construction< T > >
		is_default;

	static_assert(
		!std::is_reference< T >::value, "References not allowed" );

	void push( timer::point_type time, T t )
	{
		element_type elem{ std::move( time ), std::move( t ) };
		map_.insert( std::move( elem ) );
	}

	bool exists_before_or_at(
		timer::point_type time = timer::point_type::clock::now( ) )
	{
		if ( empty( ) )
			return false;

		return !( map_.begin( )->first > time );
	}

	typename IfEmpty::type pop( )
	{
		auto iter = map_.begin( );

		if ( iter == map_.end( ) )
			return IfEmpty::empty( );

		T value = std::move( iter->second );

		map_.erase( iter );

		if ( is_default::value )
			return value;

		return IfEmpty::value( std::move( value ) );
	}

	timer::duration_type next_time( ) const
	{
		auto iter = map_.begin( );

		if ( iter == map_.end( ) )
			timer::duration_type::max( );

		return iter->first - timer::point_type::clock::now( );
	}

	bool empty( ) const
	{
		return map_.empty( );
	}

private:
	std::multimap< timer::point_type, T > map_;
};

} // namespace q

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

#ifndef LIBQ_TIME_SET_HPP
#define LIBQ_TIME_SET_HPP

#include <q/timer.hpp>

#include <map>

namespace q {

namespace detail {

template< typename T >
struct default_construction
{
	typedef T type;

	static type empty( )
	{
		return T( );
	}

	static type value( const T& t )
	{
		return t;
	}

	static type value( T&& t )
	{
		return type( std::move( t ) );
	}
};

template< typename T >
struct time_set_less_than
{
	typedef std::tuple< timer::point_type, T > element_type;

	constexpr bool operator( )(
		const element_type& a, const element_type& b ) const
	{
		return std::get< 0 >( a ) < std::get< 0 >( b );
	}
};

} // namespace detail

/**
 * The time_set class combines time and data of type T, ordered by time.
 *
 * This is useful to order data by time, and quickly be able to find the
 * closest data by time, as well as to find how long until the next time
 * (closest to now).
 */
template<
	typename T,
	typename LessThan = detail::time_set_less_than< T >,
	typename IfEmpty = detail::default_construction< T >
>
class time_set
{
public:
	typedef std::pair< timer::point_type, T > element_type;
	typedef std::is_same< IfEmpty, detail::default_construction< T > >
		is_default;

	static_assert(
		!std::is_reference< T >::value, "References not allowed" );

	void push( timer::point_type time, T t )
	{
		map_.emplace( std::move( time ), std::move( t ) );
	}

	bool exists_before_or_at(
		timer::point_type time = timer::point_type::clock::now( ) )
	{
		if ( empty( ) )
			return false;

		return !( map_.begin( )->first > time );
	}

	T pop( )
	{
		auto iter = map_.begin( );

		if ( iter == map_.end( ) )
			return IfEmpty::empty( );

		T value = std::move( iter->second );

		map_.erase( iter );

		if ( is_default::value )
			return value;

		return IfEmpty::value( std::move( value ) );
	}

	timer::duration_type next_time( ) const
	{
		auto iter = map_.begin( );

		if ( iter == map_.end( ) )
			return timer::duration_type::max( );

		return iter->first - timer::point_type::clock::now( );
	}

	bool empty( ) const
	{
		return map_.empty( );
	}

private:
	std::multimap< timer::point_type, T > map_;
};

} // namespace q

#endif // LIBQ_TIME_SET_HPP
<|endoftext|>


<commit_before>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#include "vast/bitmap_algorithms.hpp"
#include "vast/error.hpp"
#include "vast/event.hpp"
#include "vast/ids.hpp"
#include "vast/load.hpp"
#include "vast/logger.hpp"
#include "vast/save.hpp"
#include "vast/segment_store.hpp"

#include "vast/concept/printable/to_string.hpp"
#include "vast/concept/printable/vast/error.hpp"
#include "vast/concept/printable/vast/filesystem.hpp"
#include "vast/concept/printable/vast/uuid.hpp"

#include "vast/const_table_slice_handle.hpp"
#include "vast/segment_store.hpp"
#include "vast/table_slice.hpp"
#include "vast/to_events.hpp"

namespace vast {

segment_store_ptr segment_store::make(caf::actor_system& sys, path dir,
                                      size_t max_segment_size,
                                      size_t in_memory_segments) {
  VAST_ASSERT(max_segment_size > 0);
  VAST_TRACE(VAST_ARG(dir), VAST_ARG(max_segment_size),
             VAST_ARG(in_memory_segments));
  auto x = std::make_unique<segment_store>(
    sys, std::move(dir), max_segment_size, in_memory_segments);
  // Materialize meta data of existing segments.
  if (exists(x->meta_path())) {
    VAST_DEBUG("loading segment meta data from", x->meta_path());
    if (auto err = load(sys, x->meta_path(), x->segments_)) {
      VAST_ERROR("failed to unarchive meta data:", sys.render(err));
      return nullptr;
    }
  }
  return x;
}

segment_store::~segment_store() {
  // nop
}

caf::error segment_store::put(const_table_slice_handle xs) {
  VAST_DEBUG("adding a table slice");
  VAST_TRACE(VAST_ARG(xs));
  if (auto error = builder_.add(xs))
    return error;
  if (!segments_.inject(xs->offset(), xs->offset() + xs->rows(), builder_.id()))
    return make_error(ec::unspecified, "failed to update range_map");
  if (builder_.table_slice_bytes() < max_segment_size_)
    return caf::none;
  // We have exceeded our maximum segment size and now finish.
  return flush();
}

caf::error segment_store::flush() {
  auto x = builder_.finish();
  if (!x)
    return x.error();
  auto seg_ptr = *x;
  auto filename = segment_path() / to_string(seg_ptr->id());
  if (auto err = save(sys_, filename, seg_ptr))
    return err;
  // Keep new segment in the cache.
  cache_.emplace(seg_ptr->id(), seg_ptr);
  VAST_DEBUG("wrote new segment to", filename.trim(-3));
  VAST_DEBUG("saving segment meta data");
  return save(sys_, meta_path(), segments_);
}

caf::expected<std::vector<const_table_slice_handle>>
segment_store::get(const ids& xs) {
  // Collect candidate segments by seeking through the ID set and
  // probing each ID interval.
  VAST_DEBUG("getting table slices with ids");
  VAST_TRACE(VAST_ARG(xs));
  std::vector<uuid> candidates;
  auto f = [](auto x) { return std::pair{x.left, x.right}; };
  auto g = [&](auto x) {
    auto id = x.value;
    if (candidates.empty() || candidates.back() != id)
      candidates.push_back(id);
    return caf::none;
  };
  auto begin = segments_.begin();
  auto end = segments_.end();
  if (auto error = select_with(xs, begin, end, f, g))
    return error;
  // Process candidates in reverse order for maximum LRU cache hits.
  std::vector<const_table_slice_handle> result;
  VAST_DEBUG("processing", candidates.size(), "candidates");
  for (auto cand = candidates.rbegin(); cand != candidates.rend(); ++cand) {
    auto& id = *cand;
    caf::expected<std::vector<const_table_slice_handle>> slices{caf::no_error};
    if (id == builder_.id()) {
      VAST_DEBUG("looking into builder");
      slices = builder_.lookup(xs);
    } else {
      segment_ptr seg_ptr = nullptr;
      auto i = cache_.find(id);
      if (i != cache_.end()) {
        VAST_DEBUG("got cache hit for segment", id);
        seg_ptr = i->second;
      } else {
        VAST_DEBUG("got cache miss for segment", id);
        auto fname = segment_path() / to_string(id);
        if (auto err = load(sys_, fname, seg_ptr)) {
          VAST_ERROR("unable to load segment:", sys_.render(err));
          return err;
        }
        i = cache_.emplace(id, seg_ptr).first;
      }
      VAST_ASSERT(seg_ptr != nullptr);
      slices = seg_ptr->lookup(xs);
    }
    if (!slices)
      return slices.error();
    result.reserve(result.size() + slices->size());
    result.insert(result.end(), slices->begin(), slices->end());
  }
  return result;
}

segment_store::segment_store(caf::actor_system& sys, path dir,
                             uint64_t max_segment_size, size_t in_memory_segments)
  : sys_{sys},
    dir_{std::move(dir)},
    max_segment_size_{max_segment_size},
    cache_{in_memory_segments},
    builder_{sys_} {
  // nop
}

} // namespace vast
<commit_msg>Move trace statements to the front<commit_after>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#include "vast/bitmap_algorithms.hpp"
#include "vast/error.hpp"
#include "vast/event.hpp"
#include "vast/ids.hpp"
#include "vast/load.hpp"
#include "vast/logger.hpp"
#include "vast/save.hpp"
#include "vast/segment_store.hpp"

#include "vast/concept/printable/to_string.hpp"
#include "vast/concept/printable/vast/error.hpp"
#include "vast/concept/printable/vast/filesystem.hpp"
#include "vast/concept/printable/vast/uuid.hpp"

#include "vast/const_table_slice_handle.hpp"
#include "vast/segment_store.hpp"
#include "vast/table_slice.hpp"
#include "vast/to_events.hpp"

namespace vast {

segment_store_ptr segment_store::make(caf::actor_system& sys, path dir,
                                      size_t max_segment_size,
                                      size_t in_memory_segments) {
  VAST_TRACE(VAST_ARG(dir), VAST_ARG(max_segment_size),
             VAST_ARG(in_memory_segments));
  VAST_ASSERT(max_segment_size > 0);
  auto x = std::make_unique<segment_store>(
    sys, std::move(dir), max_segment_size, in_memory_segments);
  // Materialize meta data of existing segments.
  if (exists(x->meta_path())) {
    VAST_DEBUG("loading segment meta data from", x->meta_path());
    if (auto err = load(sys, x->meta_path(), x->segments_)) {
      VAST_ERROR("failed to unarchive meta data:", sys.render(err));
      return nullptr;
    }
  }
  return x;
}

segment_store::~segment_store() {
  // nop
}

caf::error segment_store::put(const_table_slice_handle xs) {
  VAST_TRACE(VAST_ARG(xs));
  VAST_DEBUG("adding a table slice");
  if (auto error = builder_.add(xs))
    return error;
  if (!segments_.inject(xs->offset(), xs->offset() + xs->rows(), builder_.id()))
    return make_error(ec::unspecified, "failed to update range_map");
  if (builder_.table_slice_bytes() < max_segment_size_)
    return caf::none;
  // We have exceeded our maximum segment size and now finish.
  return flush();
}

caf::error segment_store::flush() {
  auto x = builder_.finish();
  if (!x)
    return x.error();
  auto seg_ptr = *x;
  auto filename = segment_path() / to_string(seg_ptr->id());
  if (auto err = save(sys_, filename, seg_ptr))
    return err;
  // Keep new segment in the cache.
  cache_.emplace(seg_ptr->id(), seg_ptr);
  VAST_DEBUG("wrote new segment to", filename.trim(-3));
  VAST_DEBUG("saving segment meta data");
  return save(sys_, meta_path(), segments_);
}

caf::expected<std::vector<const_table_slice_handle>>
segment_store::get(const ids& xs) {
  VAST_TRACE(VAST_ARG(xs));
  // Collect candidate segments by seeking through the ID set and
  // probing each ID interval.
  VAST_DEBUG("getting table slices with ids");
  std::vector<uuid> candidates;
  auto f = [](auto x) { return std::pair{x.left, x.right}; };
  auto g = [&](auto x) {
    auto id = x.value;
    if (candidates.empty() || candidates.back() != id)
      candidates.push_back(id);
    return caf::none;
  };
  auto begin = segments_.begin();
  auto end = segments_.end();
  if (auto error = select_with(xs, begin, end, f, g))
    return error;
  // Process candidates in reverse order for maximum LRU cache hits.
  std::vector<const_table_slice_handle> result;
  VAST_DEBUG("processing", candidates.size(), "candidates");
  for (auto cand = candidates.rbegin(); cand != candidates.rend(); ++cand) {
    auto& id = *cand;
    caf::expected<std::vector<const_table_slice_handle>> slices{caf::no_error};
    if (id == builder_.id()) {
      VAST_DEBUG("looking into builder");
      slices = builder_.lookup(xs);
    } else {
      segment_ptr seg_ptr = nullptr;
      auto i = cache_.find(id);
      if (i != cache_.end()) {
        VAST_DEBUG("got cache hit for segment", id);
        seg_ptr = i->second;
      } else {
        VAST_DEBUG("got cache miss for segment", id);
        auto fname = segment_path() / to_string(id);
        if (auto err = load(sys_, fname, seg_ptr)) {
          VAST_ERROR("unable to load segment:", sys_.render(err));
          return err;
        }
        i = cache_.emplace(id, seg_ptr).first;
      }
      VAST_ASSERT(seg_ptr != nullptr);
      slices = seg_ptr->lookup(xs);
    }
    if (!slices)
      return slices.error();
    result.reserve(result.size() + slices->size());
    result.insert(result.end(), slices->begin(), slices->end());
  }
  return result;
}

segment_store::segment_store(caf::actor_system& sys, path dir,
                             uint64_t max_segment_size, size_t in_memory_segments)
  : sys_{sys},
    dir_{std::move(dir)},
    max_segment_size_{max_segment_size},
    cache_{in_memory_segments},
    builder_{sys_} {
  // nop
}

} // namespace vast
<|endoftext|>


<commit_before><commit_msg>#i105852# reverted back changes with automatically fill the initials field<commit_after><|endoftext|>


<commit_before>#include "server_functions.h"
#include <string.h>

#include <iostream>
#include <sstream>

#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include <netdb.h>
#include <stdlib.h>

#include "segment.h"
#include "message.h"
#include "register_success_message.h"
#include "register_failure_message.h"
#include "register_request_message.h"
#include "loc_success_message.h"
#include "loc_failure_message.h"
#include "loc_request_message.h"

#include "rpc.h"
#include "constants.h"
#include "helper_function.h"
#include "message_types.h"

using namespace std;

//TODO:
//MANAGE CLIENT CONNECTION
//MANAGE SERVER CONNECTION
//DATABASE
//ROUND ROBIN

static map<procedure_signature, list<server_info *> * > proc_loc_dict;
static list<server_function_info *> roundRobinList;

/*
TODO:
ADD FUNCTION TO MAP
ADD FUNCTION TO ROUND ROBIN
IF FUNCTION EXISTS IN ROUND ROBIN DELETE OLD REPLACE WITH NEW (where)
*/
void registration_request_handler(RegisterRequestMessage * message, int sock){
	char * name = message->getName();
  int * argTypes = message->getArgTypes();
  string server_identifier = message->getServerIdentifier();
  int port = message->getPort();

  procedure_signature * key = new procedure_signature(name, argTypes);

  server_info * new_msg_loc = new server_info(server_identifier, port, sock);

  int status = 0;

  //if no key dosnt exist in map
	if (proc_loc_dict.find(key) == proc_loc_dict.end()) {
    //Adding to the map

    //int *memArgTypes = copyArgTypes(argTypes);
    //key = procedure_signature(name, memArgTypes);

    proc_loc_dict[key] = new list<server_info *>();
    server_info * entry = new server_info(server_identifier, port, sock);

    //Adding to roundRobinList
    server_function_info * info = new server_function_info(entry, key);
    roundRobinList.push_back(info);

  }else{

    bool sameLoc = false;
    list<service_info *> *hostList = proc_loc_dict.find[key];

    for (list<service_info *>::iterator it = hostList->begin(); it != hostList->end(); it++) {
      if(it == new_msg_loc){
        //The same procedure signature already exists on the same location
        //TODO: Move to end of round robin or something
        sameLoc = true;
      }
    }
    //Same procedure signature, different location
  	if(!sameLoc){
       hostList.push_back(new_msg_loc);
    }
  }

  RegisterSuccessMessage * success_message = new RegisterSuccessMessage(status);
  success_message->send(sock);
}

/*
TODO:
USE ROUND ROBIN TO ACCESS THE CORRECT SERVER/FUNCTION FOR THE CLIENT
*/
int location_request_handler(LocRequestMessage * message, int sock){

  bool exist = false;
	for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){
		//If the name are the same
    if(it.ps->name == message->getName() && compareArr(it.ps->argTypes, message->getArgTypes() )){
		  //When we have identified the correct procedure_signature use round robin and move that service to the end
		  roundRobinList.splice(roundRobinList.end(), roundRobinList, it);
      exist = true;
      break;
 		}
	}

  if(exist){
    LocSuccessMessage * success_message = new LocSuccessMessage(it->server_info->server_identifier, it->server_info->port);
    success_message->send(sock);
  }else{
    int reasoncode = 0;
    LocFailureMessage * failure_message = new LocFailureMessage(reasoncode);
    failure_message->send(sock);
  }

	return 0; //LOC_FAILURE
}

int request_handler(Segment * segment, int sock){
  int retval = 0;
  if(segment->getType() == MSG_TYPE_REGISTER_REQUEST){ //'LOC_REQUEST'
    Message * cast1 = segment->getMessage();
    RegistrationRequestMessage * rrm = dynamic_cast<LocRequestMessage*>(cast1);
    registration_request_handler(rrm, sock);

  }else if (segment->getType() == MSG_TYPE_LOC_REQUEST){ //'REGISTER'
    Message * cast2 = segment->getMessage();
    LocRequestMessage * lqm = dynamic_cast<LocRequestMessage*>(cast2);
    retval = location_request_handler(lqm, sock);
  }

	return retval;
}

//TODO:
//Create helper functions that can be used for rpcServer.cc
int main(){

  vector<int> myConnections;
  vector<int> myToRemove;

  int status;
  struct addrinfo hints;
  struct addrinfo* servinfo;
  struct addrinfo* p;

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  status = getaddrinfo(NULL, "0", &hints, &servinfo);

  if (status != 0) {
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
    return 0;
  }

  p = servinfo;
  int sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);

  status = bind(sock, servinfo->ai_addr, servinfo->ai_addrlen);
  status = listen(sock, 5);

  char hostname[256];
  gethostname(hostname, 256);

  struct sockaddr_in sin;
  socklen_t len = sizeof(sin);

  getsockname(sock, (struct sockaddr *)&sin, &len);

  stringstream ss;
  ss << ntohs(sin.sin_port);
  string ps = ss.str();

  cout << "BINDER_ADDRESS " << hostname << endl;
  cout << "BINDER_PORT " << ntohs(sin.sin_port) << endl;

  fd_set readfds;
  int n;
  struct sockaddr_storage their_addr;

  while(true){
    //CONNECTIONS VECTOR
    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);

    n = sock;

    for (vector<int>::iterator it = myConnections.begin();it != myConnections.end(); ++it) {
      int connection = *it;
      FD_SET(connection, &readfds);
       if (connection > n){
        n = connection;
      }
    }

    n = n+1;

    status = select(n, &readfds, NULL, NULL, NULL);

    if (status == -1) {
      cerr << "ERROR: select failed." << endl;
    } else {

      if (FD_ISSET(sock, &readfds)) {
        socklen_t addr_size = sizeof their_addr;
        int new_sock = accept(sock, (struct sockaddr*)&their_addr, &addr_size);

        if (new_sock < 0) {
          cerr << "ERROR: while accepting connection" << endl;
          close(new_sock);
          continue;
        }

        myConnections.push_back(new_sock);

      } else {

        for (vector<int>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
          int tempConnection = *it;
          if (FD_ISSET(tempConnection, &readfds)) {

            Segment * segment = 0;
            Segment::receive(sock, segment, status);

            if (status < 0) {
                RegisterFailureMessage * failure_message = new RegisterFailureMessage(status);
                failure_message->send(sock);
                return errorMsg;
            }

            if (status == 0) {
              // client has closed the connection
              myToRemove.push_back(sock);
              return errorMsg;
            }

            request_handler(segment, sock);
          }
        }
      }

      for (vector<int>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
        myConnections.erase(remove(myConnections.begin(), myConnections.end(), *it), myConnections.end());
        close(*it);
      }
      myToRemove.clear();
    }
  }

  freeaddrinfo(servinfo);
}
<commit_msg>update<commit_after>#include "server_functions.h"
#include <string.h>

#include <iostream>
#include <sstream>

#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include <netdb.h>
#include <stdlib.h>

#include "segment.h"
#include "message.h"
#include "register_success_message.h"
#include "register_failure_message.h"
#include "register_request_message.h"
#include "loc_success_message.h"
#include "loc_failure_message.h"
#include "loc_request_message.h"

#include "rpc.h"
#include "constants.h"
#include "helper_function.h"
#include "message_types.h"

using namespace std;

//TODO:
//MANAGE CLIENT CONNECTION
//MANAGE SERVER CONNECTION
//DATABASE
//ROUND ROBIN

static map<procedure_signature, list<server_info *> * > proc_loc_dict;
static list<server_function_info *> roundRobinList;

/*
TODO:
ADD FUNCTION TO MAP
ADD FUNCTION TO ROUND ROBIN
IF FUNCTION EXISTS IN ROUND ROBIN DELETE OLD REPLACE WITH NEW (where)
*/
void registration_request_handler(RegisterRequestMessage * message, int sock){
	char * name = message->getName();
  int * argTypes = message->getArgTypes();
  string server_identifier = message->getServerIdentifier();
  int port = message->getPort();

  procedure_signature * key = new procedure_signature(name, argTypes);

  server_info * new_msg_loc = new server_info(server_identifier, port, sock);

  int status = 0;

  //if no key dosnt exist in map
	if (proc_loc_dict.find(key) == proc_loc_dict.end()) {
    //Adding to the map

    //int *memArgTypes = copyArgTypes(argTypes);
    //key = procedure_signature(name, memArgTypes);

    proc_loc_dict[key] = new list<server_info *>();
    server_info * entry = new server_info(server_identifier, port, sock);

    //Adding to roundRobinList
    server_function_info * info = new server_function_info(entry, key);
    roundRobinList.push_back(info);

  }else{

    bool sameLoc = false;
    list<service_info *> *hostList = proc_loc_dict.find[key];

    for (list<service_info *>::iterator it = hostList->begin(); it != hostList->end(); it++) {
      if(it == new_msg_loc){
        //The same procedure signature already exists on the same location
        //TODO: Move to end of round robin or something
        sameLoc = true;
      }
    }
    //Same procedure signature, different location
  	if(!sameLoc){
       hostList.push_back(new_msg_loc);
    }
  }

  RegisterSuccessMessage * success_message = new RegisterSuccessMessage(status);
  success_message->send(sock);
}

/*
TODO:
USE ROUND ROBIN TO ACCESS THE CORRECT SERVER/FUNCTION FOR THE CLIENT
*/
int location_request_handler(LocRequestMessage * message, int sock){

  bool exist = false;
	for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){
		//If the name are the same
    if(it.ps->name == message->getName() && compareArr(it.ps->argTypes, message->getArgTypes() )){
		  //When we have identified the correct procedure_signature use round robin and move that service to the end
		  roundRobinList.splice(roundRobinList.end(), roundRobinList, it);
      exist = true;
      LocSuccessMessage * success_message = new LocSuccessMessage(it->server_info->server_identifier, it->server_info->port);
      success_message->send(sock);
      break;
 		}
	}

  if(!exist){
    int reasoncode = 0;
    LocFailureMessage * failure_message = new LocFailureMessage(reasoncode);
    failure_message->send(sock);
  }

	return 0; //LOC_FAILURE
}

int request_handler(Segment * segment, int sock){
  int retval = 0;
  if(segment->getType() == MSG_TYPE_REGISTER_REQUEST){ //'LOC_REQUEST'
    Message * cast1 = segment->getMessage();
    RegistrationRequestMessage * rrm = dynamic_cast<LocRequestMessage*>(cast1);
    registration_request_handler(rrm, sock);

  }else if (segment->getType() == MSG_TYPE_LOC_REQUEST){ //'REGISTER'
    Message * cast2 = segment->getMessage();
    LocRequestMessage * lqm = dynamic_cast<LocRequestMessage*>(cast2);
    retval = location_request_handler(lqm, sock);
  }

	return retval;
}

//TODO:
//Create helper functions that can be used for rpcServer.cc
int main(){

  vector<int> myConnections;
  vector<int> myToRemove;

  int status;
  struct addrinfo hints;
  struct addrinfo* servinfo;
  struct addrinfo* p;

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  status = getaddrinfo(NULL, "0", &hints, &servinfo);

  if (status != 0) {
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
    return 0;
  }

  p = servinfo;
  int sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);

  status = bind(sock, servinfo->ai_addr, servinfo->ai_addrlen);
  status = listen(sock, 5);

  char hostname[256];
  gethostname(hostname, 256);

  struct sockaddr_in sin;
  socklen_t len = sizeof(sin);

  getsockname(sock, (struct sockaddr *)&sin, &len);

  stringstream ss;
  ss << ntohs(sin.sin_port);
  string ps = ss.str();

  cout << "BINDER_ADDRESS " << hostname << endl;
  cout << "BINDER_PORT " << ntohs(sin.sin_port) << endl;

  fd_set readfds;
  int n;
  struct sockaddr_storage their_addr;

  while(true){
    //CONNECTIONS VECTOR
    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);

    n = sock;

    for (vector<int>::iterator it = myConnections.begin();it != myConnections.end(); ++it) {
      int connection = *it;
      FD_SET(connection, &readfds);
       if (connection > n){
        n = connection;
      }
    }

    n = n+1;

    status = select(n, &readfds, NULL, NULL, NULL);

    if (status == -1) {
      cerr << "ERROR: select failed." << endl;
    } else {

      if (FD_ISSET(sock, &readfds)) {
        socklen_t addr_size = sizeof their_addr;
        int new_sock = accept(sock, (struct sockaddr*)&their_addr, &addr_size);

        if (new_sock < 0) {
          cerr << "ERROR: while accepting connection" << endl;
          close(new_sock);
          continue;
        }

        myConnections.push_back(new_sock);

      } else {

        for (vector<int>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
          int tempConnection = *it;
          if (FD_ISSET(tempConnection, &readfds)) {

            Segment * segment = 0;
            Segment::receive(sock, segment, status);

            if (status < 0) {
                RegisterFailureMessage * failure_message = new RegisterFailureMessage(status);
                failure_message->send(sock);
                return errorMsg;
            }

            if (status == 0) {
              // client has closed the connection
              myToRemove.push_back(sock);
              return errorMsg;
            }

            request_handler(segment, sock);
          }
        }
      }

      for (vector<int>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
        myConnections.erase(remove(myConnections.begin(), myConnections.end(), *it), myConnections.end());
        close(*it);
      }
      myToRemove.clear();
    }
  }

  freeaddrinfo(servinfo);
}
<|endoftext|>