<commit_before>#ifndef __BTREE_NODE_HPP__
#define __BTREE_NODE_HPP__

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "btree/value.hpp"
#include "utils.hpp"
#include "buffer_cache/types.hpp"
#include "store.hpp"

/* opaque value is really just a stand in for void * it's used in some rare
 * cases where we don't actually need to know the type of the data we're
 * working with. This basically only happens in patches where we pass in the
 * value size ahead of time and can just copy the data as raw data. Still it's
 * a little be legacy and should maybe be removed */
struct opaque_value_t;

template <class Value>
class value_sizer_t;

// This will eventually be moved to a memcached-specific part of the
// project.

template <>
class value_sizer_t<memcached_value_t> {
public:
    value_sizer_t<memcached_value_t>(block_size_t bs) : block_size_(bs) { }

    int size(const memcached_value_t *value) const {
        return value->inline_size(block_size_);
    }

    bool fits(const memcached_value_t *value, int length_available) const {
        return btree_value_fits(block_size_, length_available, value);
    }

    int max_possible_size() const {
        return MAX_BTREE_VALUE_SIZE;
    }

    static block_magic_t btree_leaf_magic() {
        block_magic_t magic = { { 'l', 'e', 'a', 'f' } };
        return magic;
    }

    block_size_t block_size() const { return block_size_; }

private:
    // The block size.  It's convenient for leaf node code and for
    // some subclasses, too.
    block_size_t block_size_;

    DISABLE_COPYING(value_sizer_t<memcached_value_t>);
};

typedef value_sizer_t<memcached_value_t> memcached_value_sizer_t;

struct btree_superblock_t {
    block_magic_t magic;
    block_id_t root_block;
    block_id_t delete_queue_block;

    /* These are used for replication. replication_clock is a value that is kept synchronized
    between the master and the slave, which is updated once per second. last_sync is the value that
    replication_clock had the last time that the slave was connected to master. If we are a slave,
    replication_master_id is the creation timestamp of the master we belong to; if we are
    not a slave, it is -1 so that we can't later become a slave. If we are a master,
    replication_slave_id is the creation timestamp of the last slave we saw.

    At creation, all of them are set to 0.

    These really don't belong here! */
    repli_timestamp_t replication_clock;
    repli_timestamp_t last_sync;
    uint32_t replication_master_id, replication_slave_id;

    static const block_magic_t expected_magic;
};

//Note: This struct is stored directly on disk.  Changing it invalidates old data.
struct internal_node_t {
    block_magic_t magic;
    uint16_t npairs;
    uint16_t frontmost_offset;
    uint16_t pair_offsets[0];

    static const block_magic_t expected_magic;
};

// Here's how we represent the modification history of the leaf node.
// The last_modified time gives the modification time of the most
// recently modified key of the node.  Then, last_modified -
// earlier[0] gives the timestamp for the
// second-most-recently modified KV of the node.  In general,
// last_modified - earlier[i] gives the timestamp for the
// (i+2)th-most-recently modified KV.
//
// These values could be lies.  It is harmless to say that a key is
// newer than it really is.  So when earlier[i] overflows,
// we pin it to 0xFFFF.
struct leaf_timestamps_t {
    repli_timestamp_t last_modified;
    uint16_t earlier[NUM_LEAF_NODE_EARLIER_TIMES];
};

// Note: This struct is stored directly on disk.  Changing it invalidates old data.
// Offsets tested in leaf_node_test.cc
struct leaf_node_t {
    block_magic_t magic;
    leaf_timestamps_t times;
    uint16_t npairs;

    // The smallest offset in pair_offsets
    uint16_t frontmost_offset;
    uint16_t pair_offsets[0];

    // TODO: Remove this field, the magic value used in leaf nodes is
    // protocol-specific.
    static const block_magic_t expected_magic;
};

// Note: Changing this struct changes the format of the data stored on disk.
// If you change this struct, previous stored data will be misinterpreted.
struct btree_key_t {
    uint8_t size;
    char contents[0];
    uint16_t full_size() const {
        return size + offsetof(btree_key_t, contents);
    }
    void print() const {
        printf("%*.*s", size, size, contents);
    }
};

/* A btree_key_t can't safely be allocated because it has a zero-length 'contents' buffer. This is
to represent the fact that its size may vary on disk. A btree_key_buffer_t is a much easier-to-work-
with type. */
struct btree_key_buffer_t {
    btree_key_buffer_t() { }
    btree_key_buffer_t(const btree_key_t *k) {
        btree_key.size = k->size;
        memcpy(btree_key.contents, k->contents, k->size);
    }
    btree_key_buffer_t(const store_key_t &store_key) {
        btree_key.size = store_key.size;
        memcpy(btree_key.contents, store_key.contents, store_key.size);
    }
    btree_key_t *key() { return &btree_key; }
private:
    union {
        btree_key_t btree_key;
        char buffer[sizeof(btree_key_t) + MAX_KEY_SIZE];
    };
};

inline std::string key_to_str(const btree_key_t* key) {
    return std::string(key->contents, key->size);
}

// A node_t is either a btree_internal_node or a btree_leaf_node.
struct node_t {
    block_magic_t magic;
};

namespace node {

inline bool is_leaf(const node_t *node) {
    if (node->magic == leaf_node_t::expected_magic) {
        return true;
    }
    rassert(node->magic == internal_node_t::expected_magic);
    return false;
}

inline bool is_internal(const node_t *node) {
    if (node->magic == internal_node_t::expected_magic) {
        return true;
    }
    rassert(node->magic == leaf_node_t::expected_magic);
    return false;
}

bool has_sensible_offsets(block_size_t block_size, const node_t *node);
bool is_underfull(block_size_t block_size, const node_t *node);
bool is_mergable(block_size_t block_size, const node_t *node, const node_t *sibling, const internal_node_t *parent);
int nodecmp(const node_t *node1, const node_t *node2);

void print(const node_t *node);

}  // namespace node

inline void keycpy(btree_key_t *dest, const btree_key_t *src) {
    memcpy(dest, src, sizeof(btree_key_t) + src->size);
}

inline void valuecpy(block_size_t bs, memcached_value_t *dest, const memcached_value_t *src) {
    memcpy(dest, src, src->inline_size(bs));
}

#endif // __BTREE_NODE_HPP__
<commit_msg>Make node::is_internal() and is_leaf() work with varying leaf magics<commit_after>#ifndef __BTREE_NODE_HPP__
#define __BTREE_NODE_HPP__

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "btree/value.hpp"
#include "utils.hpp"
#include "buffer_cache/types.hpp"
#include "store.hpp"

/* opaque value is really just a stand in for void * it's used in some rare
 * cases where we don't actually need to know the type of the data we're
 * working with. This basically only happens in patches where we pass in the
 * value size ahead of time and can just copy the data as raw data. Still it's
 * a little be legacy and should maybe be removed */
struct opaque_value_t;

template <class Value>
class value_sizer_t;

// This will eventually be moved to a memcached-specific part of the
// project.

template <>
class value_sizer_t<memcached_value_t> {
public:
    value_sizer_t<memcached_value_t>(block_size_t bs) : block_size_(bs) { }

    int size(const memcached_value_t *value) const {
        return value->inline_size(block_size_);
    }

    bool fits(const memcached_value_t *value, int length_available) const {
        return btree_value_fits(block_size_, length_available, value);
    }

    int max_possible_size() const {
        return MAX_BTREE_VALUE_SIZE;
    }

    static block_magic_t btree_leaf_magic() {
        block_magic_t magic = { { 'l', 'e', 'a', 'f' } };
        return magic;
    }

    block_size_t block_size() const { return block_size_; }

private:
    // The block size.  It's convenient for leaf node code and for
    // some subclasses, too.
    block_size_t block_size_;

    DISABLE_COPYING(value_sizer_t<memcached_value_t>);
};

typedef value_sizer_t<memcached_value_t> memcached_value_sizer_t;

struct btree_superblock_t {
    block_magic_t magic;
    block_id_t root_block;
    block_id_t delete_queue_block;

    /* These are used for replication. replication_clock is a value that is kept synchronized
    between the master and the slave, which is updated once per second. last_sync is the value that
    replication_clock had the last time that the slave was connected to master. If we are a slave,
    replication_master_id is the creation timestamp of the master we belong to; if we are
    not a slave, it is -1 so that we can't later become a slave. If we are a master,
    replication_slave_id is the creation timestamp of the last slave we saw.

    At creation, all of them are set to 0.

    These really don't belong here! */
    repli_timestamp_t replication_clock;
    repli_timestamp_t last_sync;
    uint32_t replication_master_id, replication_slave_id;

    static const block_magic_t expected_magic;
};

//Note: This struct is stored directly on disk.  Changing it invalidates old data.
struct internal_node_t {
    block_magic_t magic;
    uint16_t npairs;
    uint16_t frontmost_offset;
    uint16_t pair_offsets[0];

    static const block_magic_t expected_magic;
};

// Here's how we represent the modification history of the leaf node.
// The last_modified time gives the modification time of the most
// recently modified key of the node.  Then, last_modified -
// earlier[0] gives the timestamp for the
// second-most-recently modified KV of the node.  In general,
// last_modified - earlier[i] gives the timestamp for the
// (i+2)th-most-recently modified KV.
//
// These values could be lies.  It is harmless to say that a key is
// newer than it really is.  So when earlier[i] overflows,
// we pin it to 0xFFFF.
struct leaf_timestamps_t {
    repli_timestamp_t last_modified;
    uint16_t earlier[NUM_LEAF_NODE_EARLIER_TIMES];
};

// Note: This struct is stored directly on disk.  Changing it invalidates old data.
// Offsets tested in leaf_node_test.cc
struct leaf_node_t {
    block_magic_t magic;
    leaf_timestamps_t times;
    uint16_t npairs;

    // The smallest offset in pair_offsets
    uint16_t frontmost_offset;
    uint16_t pair_offsets[0];

    // TODO: Remove this field, the magic value used in leaf nodes is
    // protocol-specific.
    static const block_magic_t expected_magic;
};

// Note: Changing this struct changes the format of the data stored on disk.
// If you change this struct, previous stored data will be misinterpreted.
struct btree_key_t {
    uint8_t size;
    char contents[0];
    uint16_t full_size() const {
        return size + offsetof(btree_key_t, contents);
    }
    void print() const {
        printf("%*.*s", size, size, contents);
    }
};

/* A btree_key_t can't safely be allocated because it has a zero-length 'contents' buffer. This is
to represent the fact that its size may vary on disk. A btree_key_buffer_t is a much easier-to-work-
with type. */
struct btree_key_buffer_t {
    btree_key_buffer_t() { }
    btree_key_buffer_t(const btree_key_t *k) {
        btree_key.size = k->size;
        memcpy(btree_key.contents, k->contents, k->size);
    }
    btree_key_buffer_t(const store_key_t &store_key) {
        btree_key.size = store_key.size;
        memcpy(btree_key.contents, store_key.contents, store_key.size);
    }
    btree_key_t *key() { return &btree_key; }
private:
    union {
        btree_key_t btree_key;
        char buffer[sizeof(btree_key_t) + MAX_KEY_SIZE];
    };
};

inline std::string key_to_str(const btree_key_t* key) {
    return std::string(key->contents, key->size);
}

// A node_t is either a btree_internal_node or a btree_leaf_node.
struct node_t {
    block_magic_t magic;
};

namespace node {

inline bool is_internal(const node_t *node) {
    if (node->magic == internal_node_t::expected_magic) {
        return true;
    }
    return false;
}

inline bool is_leaf(const node_t *node) {
    // We assume that a node is a leaf whenever it's not internal.
    // Unfortunately we cannot check the magic directly, because it differs
    // for different value types.
    // TODO: Maybe assert that the first character of the magic is 'l' or
    // something like that?
    return !is_internal(node);
}

bool has_sensible_offsets(block_size_t block_size, const node_t *node);
bool is_underfull(block_size_t block_size, const node_t *node);
bool is_mergable(block_size_t block_size, const node_t *node, const node_t *sibling, const internal_node_t *parent);
int nodecmp(const node_t *node1, const node_t *node2);

void print(const node_t *node);

}  // namespace node

inline void keycpy(btree_key_t *dest, const btree_key_t *src) {
    memcpy(dest, src, sizeof(btree_key_t) + src->size);
}

inline void valuecpy(block_size_t bs, memcached_value_t *dest, const memcached_value_t *src) {
    memcpy(dest, src, src->inline_size(bs));
}

#endif // __BTREE_NODE_HPP__
<|endoftext|>


<commit_before>/*
Copyright (c) 2015-2017 by the parties listed in the AUTHORS file.
All rights reserved.  Use of this source code is governed by
a BSD-style license that can be found in the LICENSE file.
*/

#include "toast_util_internal.hpp"
#include "toast_math_internal.hpp"

#include <sstream>
#include <algorithm>

//============================================================================//

CEREAL_CLASS_VERSION(toast::util::timer_tuple, TOAST_TIMER_VERSION)
CEREAL_CLASS_VERSION(toast::util::timing_manager, TOAST_TIMER_VERSION)

//============================================================================//

toast::util::timing_manager* toast::util::timing_manager::fgInstance = nullptr;

//============================================================================//
// static function
toast::util::timing_manager* toast::util::timing_manager::instance()
{
    if(!fgInstance) new toast::util::timing_manager();
	return fgInstance;
}

//============================================================================//
// static function
void toast::util::timing_manager::write_json(const string_t& _fname)
{
    // output stream
    std::stringstream fss;

    // ensure json write final block during destruction before the file
    // is closed
    {
        auto _space = cereal::JSONOutputArchive::Options::IndentChar::space;
        // precision, spacing, indent size
        cereal::JSONOutputArchive::Options opts(12, _space, 2);
        cereal::JSONOutputArchive oa(fss, opts);

        oa(cereal::make_nvp("timing_manager", *timing_manager::instance()));
    }

    // if another entry follows
    if(mpi_rank()+1 < mpi_size())
        fss << ",";

    int fss_len = fss.str().length();
    const int mpi_root = 0;
    int* recvcounts = nullptr;

    // Only root has the received data
    if (mpi_rank() == mpi_root)
        recvcounts = (int*) malloc( mpi_size() * sizeof(int)) ;

    MPI_Gather(&fss_len, 1, MPI_INT,
               recvcounts, 1, MPI_INT,
               mpi_root, MPI_COMM_WORLD);

    // Figure out the total length of string, and displacements for each rank
    int fss_tot_len = 0;
    int* fss_tot = nullptr;
    char* totalstring = nullptr;

    if (mpi_rank() == mpi_root)
    {
        fss_tot = (int*) malloc( mpi_size() * sizeof(int) );

        fss_tot[0] = 0;
        fss_tot_len += recvcounts[0]+1;

        for(int32_t i = 1; i < mpi_size(); ++i)
        {
            // plus one for space or \0 after words
            fss_tot_len += recvcounts[i]+1;
            fss_tot[i] = fss_tot[i-1] + recvcounts[i-1] + 1;
        }

        // allocate string, pre-fill with spaces and null terminator
        totalstring = (char*) malloc(fss_tot_len * sizeof(char));
        for(int32_t i = 0; i < fss_tot_len-1; ++i)
            totalstring[i] = ' ';
        totalstring[fss_tot_len-1] = '\0';
    }

    // Now we have the receive buffer, counts, and displacements, and
    // can gather the strings

    char* cfss = (char*) fss.str().c_str();
    MPI_Gatherv(cfss, fss_len, MPI_CHAR,
                totalstring, recvcounts, fss_tot, MPI_CHAR,
                mpi_root, MPI_COMM_WORLD);

    if (mpi_rank() == mpi_root)
    {
        ofstream_t ofs;
        ofs.open(_fname);
        ofs << "{\n\"ranks\": [" << std::endl;
        ofs << totalstring << std::endl;
        ofs << "]" << "\n}" << std::endl;
        free(totalstring);
        free(fss_tot);
        free(recvcounts);
    }

}

//============================================================================//

toast::util::timing_manager::timing_manager()
: m_report(&std::cout)
{
	if(!fgInstance) { fgInstance = this; }
    else
    {
        std::ostringstream ss;
        ss << "toast::util::timing_manager singleton has already been created";
        TOAST_THROW( ss.str().c_str() );
    }
}

//============================================================================//

toast::util::timing_manager::~timing_manager()
{
    auto close_ostream = [&] (ostream_t*& m_os)
    {
        ofstream_t* m_fos = get_ofstream(m_os);
        if(!m_fos->good() || !m_fos->is_open())
            return;
        m_fos->close();
    };

    close_ostream(m_report);

    fgInstance = nullptr;
}

//============================================================================//

toast::util::timer& toast::util::timing_manager::timer(const string_t& key,
                                                       const string_t& tag,
                                                       int32_t ncount,
                                                       int32_t nhash)
{
#if defined(DEBUG)
    if(key.find(" ") != string_t::npos)
    {
        std::stringstream ss;
        ss << "Error! Space found in tag: \"" << key << "\"";
        throw std::runtime_error(ss.str().c_str());
    }
#endif

    uint64_t sum = 0;
    for(size_t i = 0; i < key.length(); ++i)
        sum += (int64_t) key[i];
    for(size_t i = 0; i < tag.length(); ++i)
        sum += (int64_t) tag[i];

    uint64_t ref = (string_hash(key) + string_hash(tag)) * (ncount+1) * nhash;

    // if already exists, return it
    if(m_timer_map.find(ref) != m_timer_map.end())
        return m_timer_map.find(ref)->second;

    // special case of auto_timer as the first timer
    if(ncount == 1 && m_timer_list.size() == 0)
    {
        toast::util::details::base_timer::get_instance_count()--;
        ncount = 0;
    }

    std::stringstream ss;
    ss << "> " << "[" << tag << "] "; // designated as [cxx], [pyc], etc.

    // indent
    for(int64_t i = 0; i < ncount; ++i)
        ss << "  ";

    ss << std::left << key;
    toast::util::timer::propose_output_width(ss.str().length());

    m_timer_map[ref] = toast_timer_t(3, ss.str(), string_t(""));

    std::stringstream tag_ss;
    tag_ss << tag << "_" << std::left << key;
    timer_tuple_t _tuple(ref, tag_ss.str(), m_timer_map[ref]);
    m_timer_list.push_back(_tuple);

    return m_timer_map[ref];
}

//============================================================================//

void toast::util::timing_manager::report() const
{
    for(int32_t i = 0; i < mpi_size(); ++i)
    {
        // blocking
        if(mpi_is_initialized())
            MPI_Barrier(MPI_COMM_WORLD);
        // only 1 at a time
        if( i != mpi_rank() )
            continue;
        report(m_report);
    }
}

//============================================================================//

void toast::util::timing_manager::report(ostream_t* os) const
{
    auto check_stream = [&] (ostream_t*& _os, const string_t& id)
    {
        if(_os == &std::cout)
            return;
        ofstream_t* fos = get_ofstream(_os);
        if(!(fos->is_open() && fos->good()))
        {
            std::cerr << "Output stream for " << id << " is not open/valid. "
                      << "Redirecting to stdout..." << std::endl;
            _os = &std::cout;
        }
    };

    check_stream(os, "total timing report");

    for(const auto& itr : *this)
        itr.timer().stop();

    *os << "> rank " << mpi_rank() << std::endl;

    for(const auto& itr : *this)
        itr.timer().report(*os);

    os->flush();
}

//============================================================================//

void toast::util::timing_manager::set_output_stream(ostream_t& _os)
{
    m_report = &_os;
}

//============================================================================//

void toast::util::timing_manager::set_output_stream(const string_t& fname)
{
    auto ostreamop = [&] (ostream_t*& m_os, const string_t& _fname)
    {
        if(m_os != &std::cout)
            delete m_os;

        ofstream_t* _fos = new ofstream_t;
        for(int32_t i = 0; i < mpi_size(); ++i)
        {
            if(mpi_is_initialized())
                MPI_Barrier(MPI_COMM_WORLD);
            if(mpi_rank() != i)
                continue;

            if(mpi_rank() == 0)
                _fos->open(_fname);
            else
                _fos->open(_fname, std::ios_base::out | std::ios_base::app);
        }

        if(_fos->is_open() && _fos->good())
            m_os = _fos;
        else
        {
            std::cerr << "Warning! Unable to open file " << _fname << ". "
                      << "Redirecting to stdout..." << std::endl;
            _fos->close();
            delete _fos;
            m_os = &std::cout;
        }
    };

    ostreamop(m_report, fname);

}

//============================================================================//

toast::util::timing_manager::ofstream_t*
toast::util::timing_manager::get_ofstream(ostream_t* m_os) const
{
    return static_cast<ofstream_t*>(m_os);
}

//============================================================================//
<commit_msg>JSON compacting<commit_after>/*
Copyright (c) 2015-2017 by the parties listed in the AUTHORS file.
All rights reserved.  Use of this source code is governed by
a BSD-style license that can be found in the LICENSE file.
*/

#include "toast_util_internal.hpp"
#include "toast_math_internal.hpp"

#include <sstream>
#include <algorithm>

//============================================================================//

CEREAL_CLASS_VERSION(toast::util::timer_tuple, TOAST_TIMER_VERSION)
CEREAL_CLASS_VERSION(toast::util::timing_manager, TOAST_TIMER_VERSION)

//============================================================================//

toast::util::timing_manager* toast::util::timing_manager::fgInstance = nullptr;

//============================================================================//
// static function
toast::util::timing_manager* toast::util::timing_manager::instance()
{
    if(!fgInstance) new toast::util::timing_manager();
	return fgInstance;
}

//============================================================================//
// static function
void toast::util::timing_manager::write_json(const string_t& _fname)
{
    // output stream
    std::stringstream fss;

    // ensure json write final block during destruction before the file
    // is closed
    {
        auto spacing = cereal::JSONOutputArchive::Options::IndentChar::tab;
        // precision, spacing, indent size
        cereal::JSONOutputArchive::Options opts(12, spacing, 1);
        cereal::JSONOutputArchive oa(fss, opts);

        oa(cereal::make_nvp("timing_manager", *timing_manager::instance()));
    }

    // if another entry follows
    if(mpi_rank()+1 < mpi_size())
        fss << ",";

    string_t fss_str = fss.str();
    // compact the string
    for(auto citr : { "\n", "\t", "  " })
    {
        string_t itr(citr);
        string_t::size_type fpos = 0;
        while((fpos = fss_str.find(itr, fpos)) != string_t::npos)
            fss_str.replace(fpos, itr.length(), " ");
    }

    // now we need to gather the lengths of each serialization string
    int fss_len = fss_str.length();
    const int mpi_root = 0;
    int* recvcounts = nullptr;

    // Only root has the received data
    if (mpi_rank() == mpi_root)
        recvcounts = (int*) malloc( mpi_size() * sizeof(int)) ;

    MPI_Gather(&fss_len, 1, MPI_INT,
               recvcounts, 1, MPI_INT,
               mpi_root, MPI_COMM_WORLD);

    // Figure out the total length of string, and displacements for each rank
    int fss_tot_len = 0;
    int* fss_tot = nullptr;
    char* totalstring = nullptr;

    if (mpi_rank() == mpi_root)
    {
        fss_tot = (int*) malloc( mpi_size() * sizeof(int) );

        fss_tot[0] = 0;
        fss_tot_len += recvcounts[0]+1;

        for(int32_t i = 1; i < mpi_size(); ++i)
        {
            // plus one for space or \0 after words
            fss_tot_len += recvcounts[i]+1;
            fss_tot[i] = fss_tot[i-1] + recvcounts[i-1] + 1;
        }

        // allocate string, pre-fill with spaces and null terminator
        totalstring = (char*) malloc(fss_tot_len * sizeof(char));
        for(int32_t i = 0; i < fss_tot_len-1; ++i)
            totalstring[i] = ' ';
        totalstring[fss_tot_len-1] = '\0';
    }

    // Now we have the receive buffer, counts, and displacements, and
    // can gather the strings

    char* cfss = (char*) fss_str.c_str();
    MPI_Gatherv(cfss, fss_len, MPI_CHAR,
                totalstring, recvcounts, fss_tot, MPI_CHAR,
                mpi_root, MPI_COMM_WORLD);

    if (mpi_rank() == mpi_root)
    {
        ofstream_t ofs;
        ofs.open(_fname);
        ofs << "{\n\"ranks\": [" << std::endl;
        ofs << totalstring << std::endl;
        ofs << "]" << "\n}" << std::endl;
        free(totalstring);
        free(fss_tot);
        free(recvcounts);
    }

}

//============================================================================//

toast::util::timing_manager::timing_manager()
: m_report(&std::cout)
{
	if(!fgInstance) { fgInstance = this; }
    else
    {
        std::ostringstream ss;
        ss << "toast::util::timing_manager singleton has already been created";
        TOAST_THROW( ss.str().c_str() );
    }
}

//============================================================================//

toast::util::timing_manager::~timing_manager()
{
    auto close_ostream = [&] (ostream_t*& m_os)
    {
        ofstream_t* m_fos = get_ofstream(m_os);
        if(!m_fos->good() || !m_fos->is_open())
            return;
        m_fos->close();
    };

    close_ostream(m_report);

    fgInstance = nullptr;
}

//============================================================================//

toast::util::timer& toast::util::timing_manager::timer(const string_t& key,
                                                       const string_t& tag,
                                                       int32_t ncount,
                                                       int32_t nhash)
{
#if defined(DEBUG)
    if(key.find(" ") != string_t::npos)
    {
        std::stringstream ss;
        ss << "Error! Space found in tag: \"" << key << "\"";
        throw std::runtime_error(ss.str().c_str());
    }
#endif

    uint64_t sum = 0;
    for(size_t i = 0; i < key.length(); ++i)
        sum += (int64_t) key[i];
    for(size_t i = 0; i < tag.length(); ++i)
        sum += (int64_t) tag[i];

    uint64_t ref = (string_hash(key) + string_hash(tag)) * (ncount+1) * nhash;

    // if already exists, return it
    if(m_timer_map.find(ref) != m_timer_map.end())
        return m_timer_map.find(ref)->second;

    // special case of auto_timer as the first timer
    if(ncount == 1 && m_timer_list.size() == 0)
    {
        toast::util::details::base_timer::get_instance_count()--;
        ncount = 0;
    }

    std::stringstream ss;
    ss << "> " << "[" << tag << "] "; // designated as [cxx], [pyc], etc.

    // indent
    for(int64_t i = 0; i < ncount; ++i)
        ss << "  ";

    ss << std::left << key;
    toast::util::timer::propose_output_width(ss.str().length());

    m_timer_map[ref] = toast_timer_t(3, ss.str(), string_t(""));

    std::stringstream tag_ss;
    tag_ss << tag << "_" << std::left << key;
    timer_tuple_t _tuple(ref, tag_ss.str(), m_timer_map[ref]);
    m_timer_list.push_back(_tuple);

    return m_timer_map[ref];
}

//============================================================================//

void toast::util::timing_manager::report() const
{
    for(int32_t i = 0; i < mpi_size(); ++i)
    {
        // blocking
        if(mpi_is_initialized())
            MPI_Barrier(MPI_COMM_WORLD);
        // only 1 at a time
        if( i != mpi_rank() )
            continue;
        report(m_report);
    }
}

//============================================================================//

void toast::util::timing_manager::report(ostream_t* os) const
{
    auto check_stream = [&] (ostream_t*& _os, const string_t& id)
    {
        if(_os == &std::cout)
            return;
        ofstream_t* fos = get_ofstream(_os);
        if(!(fos->is_open() && fos->good()))
        {
            std::cerr << "Output stream for " << id << " is not open/valid. "
                      << "Redirecting to stdout..." << std::endl;
            _os = &std::cout;
        }
    };

    check_stream(os, "total timing report");

    for(const auto& itr : *this)
        itr.timer().stop();

    *os << "> rank " << mpi_rank() << std::endl;

    for(const auto& itr : *this)
        itr.timer().report(*os);

    os->flush();
}

//============================================================================//

void toast::util::timing_manager::set_output_stream(ostream_t& _os)
{
    m_report = &_os;
}

//============================================================================//

void toast::util::timing_manager::set_output_stream(const string_t& fname)
{
    auto ostreamop = [&] (ostream_t*& m_os, const string_t& _fname)
    {
        if(m_os != &std::cout)
            delete m_os;

        ofstream_t* _fos = new ofstream_t;
        for(int32_t i = 0; i < mpi_size(); ++i)
        {
            if(mpi_is_initialized())
                MPI_Barrier(MPI_COMM_WORLD);
            if(mpi_rank() != i)
                continue;

            if(mpi_rank() == 0)
                _fos->open(_fname);
            else
                _fos->open(_fname, std::ios_base::out | std::ios_base::app);
        }

        if(_fos->is_open() && _fos->good())
            m_os = _fos;
        else
        {
            std::cerr << "Warning! Unable to open file " << _fname << ". "
                      << "Redirecting to stdout..." << std::endl;
            _fos->close();
            delete _fos;
            m_os = &std::cout;
        }
    };

    ostreamop(m_report, fname);

}

//============================================================================//

toast::util::timing_manager::ofstream_t*
toast::util::timing_manager::get_ofstream(ostream_t* m_os) const
{
    return static_cast<ofstream_t*>(m_os);
}

//============================================================================//
<|endoftext|>


<commit_before><commit_msg>Changing the Chrome browser app name when CHROME_EXP_BUILD is defined. <commit_after><|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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 SERVER_ROUTE_HPP
#define SERVER_ROUTE_HPP

#include <regex>
#include <string>
#include <delegate>

#include "request.hpp"
#include "response.hpp"
#include "../route/path_to_regex.hpp"

namespace server {

using End_point  = delegate<void(Request_ptr, Response_ptr)>;
using Route_expr = std::regex;

struct Route {
  Route(const std::string& ex, End_point e)
    : path{ex}
    , end_point{e}
  {
    expr = route::Path_to_regex::path_to_regex(path, keys);
  }

  std::string path;
  Route_expr  expr;
  End_point   end_point;
  route::Keys keys;
  unsigned    hits;
}; //< struct Route

inline bool operator < (const Route& lhs, const Route& rhs) noexcept {
  return lhs.hits < rhs.hits;
}

} //< namespace server

#endif //< SERVER_ROUTE_HPP
<commit_msg>route: Initialize hits attribute on route construction<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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 SERVER_ROUTE_HPP
#define SERVER_ROUTE_HPP

#include <regex>
#include <string>
#include <delegate>

#include "request.hpp"
#include "response.hpp"
#include "../route/path_to_regex.hpp"

namespace server {

using End_point  = delegate<void(Request_ptr, Response_ptr)>;
using Route_expr = std::regex;

struct Route {
  Route(const std::string& ex, End_point e)
    : path{ex}
    , end_point{e}
  {
    expr = route::Path_to_regex::path_to_regex(path, keys);
  }

  std::string path;
  Route_expr  expr;
  End_point   end_point;
  route::Keys keys;
  unsigned    hits {0U};
}; //< struct Route

inline bool operator < (const Route& lhs, const Route& rhs) noexcept {
  return lhs.hits < rhs.hits;
}

} //< namespace server

#endif //< SERVER_ROUTE_HPP
<|endoftext|>


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

#include "chrome/common/chrome_constants.h"

#include "base/file_path.h"

#define FPL FILE_PATH_LITERAL

namespace chrome {

// The following should not be used for UI strings; they are meant
// for system strings only. UI changes should be made in the GRD.
#if defined(OS_WIN)
const wchar_t kBrowserProcessExecutableName[] = L"chrome.exe";
#elif defined(OS_LINUX)
const wchar_t kBrowserProcessExecutableName[] = L"chrome";
#elif defined(OS_MACOSX)
const wchar_t kBrowserProcessExecutableName[] =
#if defined(GOOGLE_CHROME_BUILD)
    L"Chrome";
#else
    L"Chromium";
#endif  // GOOGLE_CHROME_BUILD
#endif  // OS_*
#if defined(OS_WIN)
const wchar_t kBrowserProcessExecutablePath[] = L"chrome.exe";
#elif defined(OS_LINUX)
const wchar_t kBrowserProcessExecutablePath[] = L"chrome";
#elif defined(OS_MACOSX)
const wchar_t kBrowserProcessExecutablePath[] =
#if defined(GOOGLE_CHROME_BUILD)
    L"Google Chrome.app/Contents/MacOS/Google Chrome";
#else
    L"Chromium.app/Contents/MacOS/Chromium";
#endif  // GOOGLE_CHROME_BUILD
#endif  // OS_*
#if defined(GOOGLE_CHROME_BUILD)
const wchar_t kBrowserAppName[] = L"Chrome";
const char    kStatsFilename[] = "ChromeStats2";
#else
const wchar_t kBrowserAppName[] = L"Chromium";
const char    kStatsFilename[] = "ChromiumStats2";
#endif
const wchar_t kExternalTabWindowClass[] = L"Chrome_ExternalTabContainer";
const wchar_t kMessageWindowClass[] = L"Chrome_MessageWindow";
const wchar_t kCrashReportLog[] = L"Reported Crashes.txt";
const wchar_t kTestingInterfaceDLL[] = L"testing_interface.dll";
const wchar_t kNotSignedInProfile[] = L"Default";
const wchar_t kNotSignedInID[] = L"not-signed-in";
const wchar_t kBrowserResourcesDll[] = L"chrome.dll";
const FilePath::CharType kExtensionFileExtension[] = FPL("crx");

// filenames
const FilePath::CharType kArchivedHistoryFilename[] = FPL("Archived History");
const FilePath::CharType kCacheDirname[] = FPL("Cache");
const FilePath::CharType kMediaCacheDirname[] = FPL("Media Cache");
const FilePath::CharType kOffTheRecordMediaCacheDirname[] =
    FPL("Incognito Media Cache");
const wchar_t kChromePluginDataDirname[] = L"Plugin Data";
const FilePath::CharType kCookieFilename[] = FPL("Cookies");
const FilePath::CharType kExtensionsCookieFilename[] = FPL("Extension Cookies");
const FilePath::CharType kHistoryFilename[] = FPL("History");
const FilePath::CharType kLocalStateFilename[] = FPL("Local State");
const FilePath::CharType kPreferencesFilename[] = FPL("Preferences");
const FilePath::CharType kSafeBrowsingFilename[] = FPL("Safe Browsing");
// WARNING: SingletonSocket can't contain spaces, because otherwise
// chrome_process_util_linux would be broken.
const FilePath::CharType kSingletonSocketFilename[] = FPL("SingletonSocket");
const FilePath::CharType kThumbnailsFilename[] = FPL("Thumbnails");
const wchar_t kUserDataDirname[] = L"User Data";
const FilePath::CharType kUserScriptsDirname[] = FPL("User Scripts");
const FilePath::CharType kWebDataFilename[] = FPL("Web Data");
const FilePath::CharType kBookmarksFileName[] = FPL("Bookmarks");
const FilePath::CharType kHistoryBookmarksFileName[] =
    FPL("Bookmarks From History");
const FilePath::CharType kCustomDictionaryFileName[] =
    FPL("Custom Dictionary.txt");

// This number used to be limited to 32 in the past (see b/535234).
const unsigned int kMaxRendererProcessCount = 42;
const int kStatsMaxThreads = 32;
const int kStatsMaxCounters = 300;

// We don't enable record mode in the released product because users could
// potentially be tricked into running a product in record mode without
// knowing it.  Enable in debug builds.  Playback mode is allowed always,
// because it is useful for testing and not hazardous by itself.
#ifndef NDEBUG
const bool kRecordModeEnabled = true;
#else
const bool kRecordModeEnabled = false;
#endif

}  // namespace chrome
<commit_msg>Fix another name I missed. Review URL: http://codereview.chromium.org/113727<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/chrome_constants.h"

#include "base/file_path.h"

#define FPL FILE_PATH_LITERAL

namespace chrome {

// The following should not be used for UI strings; they are meant
// for system strings only. UI changes should be made in the GRD.
#if defined(OS_WIN)
const wchar_t kBrowserProcessExecutableName[] = L"chrome.exe";
#elif defined(OS_LINUX)
const wchar_t kBrowserProcessExecutableName[] = L"chrome";
#elif defined(OS_MACOSX)
const wchar_t kBrowserProcessExecutableName[] =
#if defined(GOOGLE_CHROME_BUILD)
    L"Google Chrome";
#else
    L"Chromium";
#endif  // GOOGLE_CHROME_BUILD
#endif  // OS_*
#if defined(OS_WIN)
const wchar_t kBrowserProcessExecutablePath[] = L"chrome.exe";
#elif defined(OS_LINUX)
const wchar_t kBrowserProcessExecutablePath[] = L"chrome";
#elif defined(OS_MACOSX)
const wchar_t kBrowserProcessExecutablePath[] =
#if defined(GOOGLE_CHROME_BUILD)
    L"Google Chrome.app/Contents/MacOS/Google Chrome";
#else
    L"Chromium.app/Contents/MacOS/Chromium";
#endif  // GOOGLE_CHROME_BUILD
#endif  // OS_*
#if defined(GOOGLE_CHROME_BUILD)
const wchar_t kBrowserAppName[] = L"Chrome";
const char    kStatsFilename[] = "ChromeStats2";
#else
const wchar_t kBrowserAppName[] = L"Chromium";
const char    kStatsFilename[] = "ChromiumStats2";
#endif
const wchar_t kExternalTabWindowClass[] = L"Chrome_ExternalTabContainer";
const wchar_t kMessageWindowClass[] = L"Chrome_MessageWindow";
const wchar_t kCrashReportLog[] = L"Reported Crashes.txt";
const wchar_t kTestingInterfaceDLL[] = L"testing_interface.dll";
const wchar_t kNotSignedInProfile[] = L"Default";
const wchar_t kNotSignedInID[] = L"not-signed-in";
const wchar_t kBrowserResourcesDll[] = L"chrome.dll";
const FilePath::CharType kExtensionFileExtension[] = FPL("crx");

// filenames
const FilePath::CharType kArchivedHistoryFilename[] = FPL("Archived History");
const FilePath::CharType kCacheDirname[] = FPL("Cache");
const FilePath::CharType kMediaCacheDirname[] = FPL("Media Cache");
const FilePath::CharType kOffTheRecordMediaCacheDirname[] =
    FPL("Incognito Media Cache");
const wchar_t kChromePluginDataDirname[] = L"Plugin Data";
const FilePath::CharType kCookieFilename[] = FPL("Cookies");
const FilePath::CharType kExtensionsCookieFilename[] = FPL("Extension Cookies");
const FilePath::CharType kHistoryFilename[] = FPL("History");
const FilePath::CharType kLocalStateFilename[] = FPL("Local State");
const FilePath::CharType kPreferencesFilename[] = FPL("Preferences");
const FilePath::CharType kSafeBrowsingFilename[] = FPL("Safe Browsing");
// WARNING: SingletonSocket can't contain spaces, because otherwise
// chrome_process_util_linux would be broken.
const FilePath::CharType kSingletonSocketFilename[] = FPL("SingletonSocket");
const FilePath::CharType kThumbnailsFilename[] = FPL("Thumbnails");
const wchar_t kUserDataDirname[] = L"User Data";
const FilePath::CharType kUserScriptsDirname[] = FPL("User Scripts");
const FilePath::CharType kWebDataFilename[] = FPL("Web Data");
const FilePath::CharType kBookmarksFileName[] = FPL("Bookmarks");
const FilePath::CharType kHistoryBookmarksFileName[] =
    FPL("Bookmarks From History");
const FilePath::CharType kCustomDictionaryFileName[] =
    FPL("Custom Dictionary.txt");

// This number used to be limited to 32 in the past (see b/535234).
const unsigned int kMaxRendererProcessCount = 42;
const int kStatsMaxThreads = 32;
const int kStatsMaxCounters = 300;

// We don't enable record mode in the released product because users could
// potentially be tricked into running a product in record mode without
// knowing it.  Enable in debug builds.  Playback mode is allowed always,
// because it is useful for testing and not hazardous by itself.
#ifndef NDEBUG
const bool kRecordModeEnabled = true;
#else
const bool kRecordModeEnabled = false;
#endif

}  // namespace chrome
<|endoftext|>


<commit_before>/***********************************************************************
 row.cpp - Implements the Row class.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999-2001 by MySQL AB, and
 (c) 2004-2007 by Educational Technology Resources, Inc.  Others may
 also hold copyrights on code in this file.  See the CREDITS file in
 the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 MySQL++ is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "row.h"
#include "result.h"
#include "exceptions.h"

namespace mysqlpp {

Row::Row(MYSQL_ROW d, const ResUse* r, const unsigned long* lengths,
		bool throw_exceptions) :
OptionalExceptions(throw_exceptions),
initialized_(false)
{
	if (d && r) {
		size_type size = r->num_fields();
		data_.reserve(size);
		for (size_type i = 0; i < size; ++i) {
			bool is_null = d[i] == 0;
			data_.push_back(value_type(
					is_null ? "NULL" : d[i],
					is_null ? 4 : lengths[i],
					r->field_type(i),
					is_null));
		}

		field_names_ = r->field_names();
		initialized_ = true;
	}
	else if (throw_exceptions) {
		throw ObjectNotInitialized("ROW or RES is NULL");
	}
}

const Row::value_type&
Row::operator [](const char* field) const
{
	size_type si = field_num(field);
	if (si < size()) {
		return at(si);
	}
	else {
		throw BadFieldName(field);
	}
}

Row::size_type
Row::field_num(const char* name) const
{
	if (field_names_) {
		return (*field_names_)[name];
	}
	else {
		if (throw_exceptions()) {
			throw BadFieldName(name);
		}
		else {
			return 0;
		}
	}
}

value_list_ba<FieldNames, do_nothing_type0>
Row::field_list(const char* d) const
{
	return value_list_ba<FieldNames, do_nothing_type0>
			(*field_names_, d, do_nothing);
}

template <class Manip>
value_list_ba<FieldNames, Manip>
Row::field_list(const char *d, Manip m) const
{
	return value_list_ba<FieldNames, Manip>(*field_names_, d, m);
}

template <class Manip>
value_list_b<FieldNames, Manip>
Row::field_list(const char *d, Manip m, const std::vector<bool>& vb) const
{
	return value_list_b<FieldNames, Manip>(*field_names_, vb, d, m);
}

value_list_b<FieldNames, quote_type0>
Row::field_list(const char* d, const std::vector<bool>& vb) const
{
	return value_list_b<FieldNames, quote_type0>(*field_names_,
			vb, d, quote);
}

value_list_b<FieldNames, quote_type0>
Row::field_list(const std::vector<bool>& vb) const
{
	return value_list_b<FieldNames, quote_type0>(*field_names_,
			vb, ",", quote);
}

template <class Manip> value_list_b<FieldNames, Manip>
Row::field_list(const char* d, Manip m, bool t0, bool t1, bool t2,
		bool t3, bool t4, bool t5, bool t6, bool t7, bool t8, bool t9,
		bool ta, bool tb, bool tc) const
{
	std::vector<bool> vb;
	create_vector(field_names_->size(), vb, t0, t1, t2, t3, t4,
			t5, t6, t7, t8, t9, ta, tb, tc);
	return value_list_b<FieldNames, Manip>(*field_names_, vb, d, m);
}

value_list_b<FieldNames, quote_type0>
Row::field_list(const char *d, bool t0, bool t1, bool t2, bool t3,
		bool t4, bool t5, bool t6, bool t7, bool t8, bool t9, bool ta,
		bool tb, bool tc) const
{
	std::vector<bool> vb;
	create_vector(field_names_->size(), vb, t0, t1, t2, t3, t4,
			t5, t6, t7, t8, t9, ta, tb, tc);
	return value_list_b<FieldNames, quote_type0>(*field_names_,
			vb, d, quote);
}

value_list_b<FieldNames, quote_type0>
Row::field_list(bool t0, bool t1, bool t2, bool t3, bool t4, bool t5,
		bool t6, bool t7, bool t8, bool t9, bool ta, bool tb,
		bool tc) const
{
	std::vector<bool> vb;
	create_vector(field_names_->size(), vb, t0, t1, t2, t3, t4,
			t5, t6, t7, t8, t9, ta, tb, tc);
	return value_list_b<FieldNames, quote_type0>(*field_names_,
			vb, ",", quote);
}

equal_list_ba<FieldNames, Row, quote_type0>
Row::equal_list(const char* d, const char* e) const
{
	return equal_list_ba<FieldNames, Row, quote_type0>(
			*field_names_, *this, d, e, quote);
}

template <class Manip>
equal_list_ba<FieldNames, Row, Manip>
Row::equal_list(const char* d, const char* e, Manip m) const
{
	return equal_list_ba<FieldNames, Row, Manip>(
			*field_names_, *this, d, e, m);
}

} // end namespace mysqlpp

<commit_msg>If exceptions are suppressed on Row, operator[](const char*) will now return an empty value; BadFieldName is no longer a mandatory exception. This is probably not necessary now, but it will be in SSQLSv2, with the subset population changes: it will be "legal" to ask for a field in a Row that doesn't exist.  We'll use NoExceptions(row) in the populate method.<commit_after>/***********************************************************************
 row.cpp - Implements the Row class.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999-2001 by MySQL AB, and
 (c) 2004-2007 by Educational Technology Resources, Inc.  Others may
 also hold copyrights on code in this file.  See the CREDITS file in
 the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 MySQL++ is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "row.h"
#include "result.h"
#include "exceptions.h"

namespace mysqlpp {

Row::Row(MYSQL_ROW d, const ResUse* r, const unsigned long* lengths,
		bool throw_exceptions) :
OptionalExceptions(throw_exceptions),
initialized_(false)
{
	if (d && r) {
		size_type size = r->num_fields();
		data_.reserve(size);
		for (size_type i = 0; i < size; ++i) {
			bool is_null = d[i] == 0;
			data_.push_back(value_type(
					is_null ? "NULL" : d[i],
					is_null ? 4 : lengths[i],
					r->field_type(i),
					is_null));
		}

		field_names_ = r->field_names();
		initialized_ = true;
	}
	else if (throw_exceptions) {
		throw ObjectNotInitialized("ROW or RES is NULL");
	}
}

const Row::value_type&
Row::operator [](const char* field) const
{
	size_type si = field_num(field);
	if (si < size()) {
		return at(si);
	}
	else {
		if (throw_exceptions()) {
			throw BadFieldName(field);
		}
		else {
			static value_type empty;
			return empty;
		}
	}
}

Row::size_type
Row::field_num(const char* name) const
{
	if (field_names_) {
		return (*field_names_)[name];
	}
	else {
		if (throw_exceptions()) {
			throw BadFieldName(name);
		}
		else {
			return 0;
		}
	}
}

value_list_ba<FieldNames, do_nothing_type0>
Row::field_list(const char* d) const
{
	return value_list_ba<FieldNames, do_nothing_type0>
			(*field_names_, d, do_nothing);
}

template <class Manip>
value_list_ba<FieldNames, Manip>
Row::field_list(const char *d, Manip m) const
{
	return value_list_ba<FieldNames, Manip>(*field_names_, d, m);
}

template <class Manip>
value_list_b<FieldNames, Manip>
Row::field_list(const char *d, Manip m, const std::vector<bool>& vb) const
{
	return value_list_b<FieldNames, Manip>(*field_names_, vb, d, m);
}

value_list_b<FieldNames, quote_type0>
Row::field_list(const char* d, const std::vector<bool>& vb) const
{
	return value_list_b<FieldNames, quote_type0>(*field_names_,
			vb, d, quote);
}

value_list_b<FieldNames, quote_type0>
Row::field_list(const std::vector<bool>& vb) const
{
	return value_list_b<FieldNames, quote_type0>(*field_names_,
			vb, ",", quote);
}

template <class Manip> value_list_b<FieldNames, Manip>
Row::field_list(const char* d, Manip m, bool t0, bool t1, bool t2,
		bool t3, bool t4, bool t5, bool t6, bool t7, bool t8, bool t9,
		bool ta, bool tb, bool tc) const
{
	std::vector<bool> vb;
	create_vector(field_names_->size(), vb, t0, t1, t2, t3, t4,
			t5, t6, t7, t8, t9, ta, tb, tc);
	return value_list_b<FieldNames, Manip>(*field_names_, vb, d, m);
}

value_list_b<FieldNames, quote_type0>
Row::field_list(const char *d, bool t0, bool t1, bool t2, bool t3,
		bool t4, bool t5, bool t6, bool t7, bool t8, bool t9, bool ta,
		bool tb, bool tc) const
{
	std::vector<bool> vb;
	create_vector(field_names_->size(), vb, t0, t1, t2, t3, t4,
			t5, t6, t7, t8, t9, ta, tb, tc);
	return value_list_b<FieldNames, quote_type0>(*field_names_,
			vb, d, quote);
}

value_list_b<FieldNames, quote_type0>
Row::field_list(bool t0, bool t1, bool t2, bool t3, bool t4, bool t5,
		bool t6, bool t7, bool t8, bool t9, bool ta, bool tb,
		bool tc) const
{
	std::vector<bool> vb;
	create_vector(field_names_->size(), vb, t0, t1, t2, t3, t4,
			t5, t6, t7, t8, t9, ta, tb, tc);
	return value_list_b<FieldNames, quote_type0>(*field_names_,
			vb, ",", quote);
}

equal_list_ba<FieldNames, Row, quote_type0>
Row::equal_list(const char* d, const char* e) const
{
	return equal_list_ba<FieldNames, Row, quote_type0>(
			*field_names_, *this, d, e, quote);
}

template <class Manip>
equal_list_ba<FieldNames, Row, Manip>
Row::equal_list(const char* d, const char* e, Manip m) const
{
	return equal_list_ba<FieldNames, Row, Manip>(
			*field_names_, *this, d, e, m);
}

} // end namespace mysqlpp

<|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>
#include <vector>
#include <boost/python.hpp>
#include <boost/python/numpy.hpp>
#include <numpy/ndarrayobject.h>
#include "boost/tuple/tuple.hpp"
#include "boost/python/object.hpp"
#include <../include/API.h>
//#include <../include/connected_components.h>

namespace bpn = boost::python::numpy;
namespace bp =  boost::python;

typedef boost::tuple< std::vector< std::vector<uint32_t> >, std::vector<uint32_t> > Custom_tuple;

struct VecToArray
{//converts a vector<uint32_t> to a numpy array
    static PyObject * convert(const std::vector<uint32_t> & vec)
    {
        npy_intp dims = vec.size();
        PyObject * obj = PyArray_SimpleNew(1, &dims, NPY_UINT32);
        void * arr_data = PyArray_DATA((PyArrayObject*)obj);
        memcpy(arr_data, &vec[0], dims * sizeof(uint32_t));
        return obj;
    }
};

struct VecToArray_float
{//converts a vector<uint32_t> to a numpy array
    static PyObject * convert(const std::vector<float> & vec)
    {
        npy_intp dims = vec.size();
        PyObject * obj = PyArray_SimpleNew(1, &dims, NPY_FLOAT32);
        void * arr_data = PyArray_DATA((PyArrayObject*)obj);
        memcpy(arr_data, &vec[0], dims * sizeof(float));
        return obj;
    }
};

template<class T>
struct VecvecToList
{//converts a vector< vector<T> > to a list
        static PyObject* convert(const std::vector< std::vector<T> > & vecvec)
    {
        boost::python::list* pylistlist = new boost::python::list();
        for(size_t i = 0; i < vecvec.size(); i++)
        {
            boost::python::list* pylist = new boost::python::list();
            for(size_t j = 0; j < vecvec[i].size(); j++)
            {
                pylist->append(vecvec[i][j]);
            }
            pylistlist->append((pylist, pylist[0]));
        }
        return pylistlist->ptr();
    }
};

struct to_py_tuple
{//converts output to a python tuple
    static PyObject* convert(const Custom_tuple& c_tuple){
        bp::list values;
        //add all c_tuple items to "values" list

        PyObject * vecvec_pyo = VecvecToList<uint32_t>::convert(c_tuple.get<0>());
        PyObject * vec_pyo = VecToArray::convert(c_tuple.get<1>());

        values.append(bp::handle<>(bp::borrowed(vecvec_pyo)));
        values.append(bp::handle<>(bp::borrowed(vec_pyo)));

        return bp::incref( bp::tuple( values ).ptr() );
    }
};

PyObject * cutpursuit(const bpn::ndarray & obs, const bpn::ndarray & source, const bpn::ndarray & target,const bpn::ndarray & edge_weight,
                      float lambda, const int cutoff, const int spatial)
{//read data and run the L0-cut pursuit partition algorithm
    srand(0);

    const uint32_t n_ver = bp::len(obs);
    const uint32_t n_edg = bp::len(source);
    const uint32_t n_obs = bp::len(obs[0]);
    const float * obs_data = reinterpret_cast<float*>(obs.get_data());
    const uint32_t * source_data = reinterpret_cast<uint32_t*>(source.get_data());
    const uint32_t * target_data = reinterpret_cast<uint32_t*>(target.get_data());
    const float * edge_weight_data = reinterpret_cast<float*>(edge_weight.get_data());
    std::vector<float> solution(n_ver *n_obs);
    //float solution [n_ver * n_obs];
    std::vector<float> node_weight(n_ver, 1.0f);
    std::vector<uint32_t> in_component(n_ver,0);
    std::vector< std::vector<uint32_t> > components(1,std::vector<uint32_t>(1,0.f));
    if (spatial == 0)
    {
        CP::cut_pursuit<float>(n_ver, n_edg, n_obs, obs_data, source_data, target_data, edge_weight_data, &node_weight[0]
                 , solution.data(), in_component, components, lambda, (uint32_t)cutoff,  2.f, 4.f, 1.f);
    }
    else
    {
        CP::cut_pursuit<float>(n_ver, n_edg, n_obs, obs_data, source_data, target_data, edge_weight_data, &node_weight[0]
                 , solution.data(), in_component, components, lambda, (uint32_t)cutoff,  2.f, 4.f, 1.f);
    }
    return to_py_tuple::convert(Custom_tuple(components, in_component));
}

PyObject * cutpursuit2(const bpn::ndarray & obs, const bpn::ndarray & source, const bpn::ndarray & target,const bpn::ndarray & edge_weight,
                       const bpn::ndarray & node_weight, float lambda)
{//read data and run the L0-cut pursuit partition algorithm
    srand(0);
std::cout << std::endl;
    const uint32_t n_ver = bp::len(obs);
    const uint32_t n_edg = bp::len(source);
    const uint32_t n_obs = bp::len(obs[0]);
    const float * obs_data = reinterpret_cast<float*>(obs.get_data());
    const uint32_t * source_data = reinterpret_cast<uint32_t*>(source.get_data());
    const uint32_t * target_data = reinterpret_cast<uint32_t*>(target.get_data());
    const float * edge_weight_data = reinterpret_cast<float*>(edge_weight.get_data());
    const float * node_weight_data = reinterpret_cast<float*>(node_weight.get_data());
    std::vector<float> solution(n_ver *n_obs);
    //float solution [n_ver * n_obs];
    //std::vector<float> node_weight(n_ver, 1.0f);
    std::vector<uint32_t> in_component(n_ver,0);
    std::vector< std::vector<uint32_t> > components(1,std::vector<uint32_t>(1,0.f));
    CP::cut_pursuit<float>(n_ver, n_edg, n_obs, obs_data, source_data, target_data, edge_weight_data, node_weight_data
                 , solution.data(), in_component, components, lambda, (uint32_t)0,  2.f, 4.f, 1.f);
    return to_py_tuple::convert(Custom_tuple(components, in_component));
}

BOOST_PYTHON_MODULE(libcp)
{
    _import_array();
    Py_Initialize();
    bpn::initialize();
    bp::to_python_converter< Custom_tuple, to_py_tuple>();
    //def("connected_comp", connected_comp);
    def("cutpursuit", cutpursuit);
    def("cutpursuit", cutpursuit, (bp::args("cutoff")=0, bp::args("spatial")=0));
    def("cutpursuit2", cutpursuit2);
}

<commit_msg>fixed the call to spatial<commit_after>#include <iostream>
#include <cstdio>
#include <vector>
#include <boost/python.hpp>
#include <boost/python/numpy.hpp>
#include <numpy/ndarrayobject.h>
#include "boost/tuple/tuple.hpp"
#include "boost/python/object.hpp"
#include <../include/API.h>
//#include <../include/connected_components.h>

namespace bpn = boost::python::numpy;
namespace bp =  boost::python;

typedef boost::tuple< std::vector< std::vector<uint32_t> >, std::vector<uint32_t> > Custom_tuple;

struct VecToArray
{//converts a vector<uint32_t> to a numpy array
    static PyObject * convert(const std::vector<uint32_t> & vec)
    {
        npy_intp dims = vec.size();
        PyObject * obj = PyArray_SimpleNew(1, &dims, NPY_UINT32);
        void * arr_data = PyArray_DATA((PyArrayObject*)obj);
        memcpy(arr_data, &vec[0], dims * sizeof(uint32_t));
        return obj;
    }
};

struct VecToArray_float
{//converts a vector<uint32_t> to a numpy array
    static PyObject * convert(const std::vector<float> & vec)
    {
        npy_intp dims = vec.size();
        PyObject * obj = PyArray_SimpleNew(1, &dims, NPY_FLOAT32);
        void * arr_data = PyArray_DATA((PyArrayObject*)obj);
        memcpy(arr_data, &vec[0], dims * sizeof(float));
        return obj;
    }
};

template<class T>
struct VecvecToList
{//converts a vector< vector<T> > to a list
        static PyObject* convert(const std::vector< std::vector<T> > & vecvec)
    {
        boost::python::list* pylistlist = new boost::python::list();
        for(size_t i = 0; i < vecvec.size(); i++)
        {
            boost::python::list* pylist = new boost::python::list();
            for(size_t j = 0; j < vecvec[i].size(); j++)
            {
                pylist->append(vecvec[i][j]);
            }
            pylistlist->append((pylist, pylist[0]));
        }
        return pylistlist->ptr();
    }
};

struct to_py_tuple
{//converts output to a python tuple
    static PyObject* convert(const Custom_tuple& c_tuple){
        bp::list values;
        //add all c_tuple items to "values" list

        PyObject * vecvec_pyo = VecvecToList<uint32_t>::convert(c_tuple.get<0>());
        PyObject * vec_pyo = VecToArray::convert(c_tuple.get<1>());

        values.append(bp::handle<>(bp::borrowed(vecvec_pyo)));
        values.append(bp::handle<>(bp::borrowed(vec_pyo)));

        return bp::incref( bp::tuple( values ).ptr() );
    }
};

PyObject * cutpursuit(const bpn::ndarray & obs, const bpn::ndarray & source, const bpn::ndarray & target,const bpn::ndarray & edge_weight,
                      float lambda, const int cutoff, const int spatial)
{//read data and run the L0-cut pursuit partition algorithm
    srand(0);

    const uint32_t n_ver = bp::len(obs);
    const uint32_t n_edg = bp::len(source);
    const uint32_t n_obs = bp::len(obs[0]);
    const float * obs_data = reinterpret_cast<float*>(obs.get_data());
    const uint32_t * source_data = reinterpret_cast<uint32_t*>(source.get_data());
    const uint32_t * target_data = reinterpret_cast<uint32_t*>(target.get_data());
    const float * edge_weight_data = reinterpret_cast<float*>(edge_weight.get_data());
    std::vector<float> solution(n_ver *n_obs);
    //float solution [n_ver * n_obs];
    std::vector<float> node_weight(n_ver, 1.0f);
    std::vector<uint32_t> in_component(n_ver,0);
    std::vector< std::vector<uint32_t> > components(1,std::vector<uint32_t>(1,0.f));
    if (spatial == 0)
    {
        CP::cut_pursuit<float>(n_ver, n_edg, n_obs, obs_data, source_data, target_data, edge_weight_data, &node_weight[0]
                 , solution.data(), in_component, components, lambda, (uint32_t)cutoff,  1.f, 4.f, 1.f);
    }
    else
    {
        CP::cut_pursuit<float>(n_ver, n_edg, n_obs, obs_data, source_data, target_data, edge_weight_data, &node_weight[0]
                 , solution.data(), in_component, components, lambda, (uint32_t)cutoff,  2.f, 4.f, 1.f);
    }
    return to_py_tuple::convert(Custom_tuple(components, in_component));
}

PyObject * cutpursuit2(const bpn::ndarray & obs, const bpn::ndarray & source, const bpn::ndarray & target,const bpn::ndarray & edge_weight,
                       const bpn::ndarray & node_weight, float lambda)
{//read data and run the L0-cut pursuit partition algorithm
    srand(0);
std::cout << std::endl;
    const uint32_t n_ver = bp::len(obs);
    const uint32_t n_edg = bp::len(source);
    const uint32_t n_obs = bp::len(obs[0]);
    const float * obs_data = reinterpret_cast<float*>(obs.get_data());
    const uint32_t * source_data = reinterpret_cast<uint32_t*>(source.get_data());
    const uint32_t * target_data = reinterpret_cast<uint32_t*>(target.get_data());
    const float * edge_weight_data = reinterpret_cast<float*>(edge_weight.get_data());
    const float * node_weight_data = reinterpret_cast<float*>(node_weight.get_data());
    std::vector<float> solution(n_ver *n_obs);
    //float solution [n_ver * n_obs];
    //std::vector<float> node_weight(n_ver, 1.0f);
    std::vector<uint32_t> in_component(n_ver,0);
    std::vector< std::vector<uint32_t> > components(1,std::vector<uint32_t>(1,0.f));
    CP::cut_pursuit<float>(n_ver, n_edg, n_obs, obs_data, source_data, target_data, edge_weight_data, node_weight_data
                 , solution.data(), in_component, components, lambda, (uint32_t)0,  2.f, 4.f, 1.f);
    return to_py_tuple::convert(Custom_tuple(components, in_component));
}

BOOST_PYTHON_MODULE(libcp)
{
    _import_array();
    Py_Initialize();
    bpn::initialize();
    bp::to_python_converter< Custom_tuple, to_py_tuple>();
    //def("connected_comp", connected_comp);
    def("cutpursuit", cutpursuit);
    def("cutpursuit", cutpursuit, (bp::args("cutoff")=0, bp::args("spatial")=0));
    def("cutpursuit2", cutpursuit2);
}

<|endoftext|>


<commit_before>#include "directories.h"
#include "sourcefile.h"
#include "logging.h"
#include "singletons.h"
#include <algorithm>
#include <unordered_set>

#include <iostream> //TODO: remove
using namespace std; //TODO: remove

namespace sigc {
  SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
}

Directories::Directories() : stop_update_thread(false) {
  DEBUG("adding treeview to scrolledwindow");
  add(tree_view);
  set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  tree_store = Gtk::TreeStore::create(column_record);
  tree_view.set_model(tree_store);
  tree_view.append_column("", column_record.name);
  tree_store->set_sort_column(column_record.id, Gtk::SortType::SORT_ASCENDING);

  tree_view.signal_row_activated().connect([this](const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column){
    INFO("Directory navigation");
    auto iter = tree_store->get_iter(path);
    if (iter) {
      auto path_str=iter->get_value(column_record.path);
      if(path_str!="") {
        if (boost::filesystem::is_directory(boost::filesystem::path(path_str))) {
          tree_view.row_expanded(path) ? tree_view.collapse_row(path) : tree_view.expand_row(path, false);
        } else {
          if(on_row_activated)
            on_row_activated(path_str);
        }
      }
    }
  });

  tree_view.signal_test_expand_row().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){
    if(iter->children().begin()->get_value(column_record.path)=="") {
      update_mutex.lock();
      add_path(iter->get_value(column_record.path), *iter);
      update_mutex.unlock();
    }
    return false;
  });
  tree_view.signal_row_collapsed().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){
    update_mutex.lock();
    last_write_times.erase(iter->get_value(column_record.path));
    update_mutex.unlock();
    auto children=iter->children();
    if(children) {
      while(children) {
        tree_store->erase(children.begin());
      }
      auto child=tree_store->append(iter->children());
      child->set_value(column_record.name, std::string("(empty)"));
    }
  });

  update_dispatcher.connect([this](){
    update_mutex.lock();
    for(auto &path: update_paths) {
      if(last_write_times.count(path)>0)
        add_path(path, last_write_times.at(path).first);
    }
    update_paths.clear();
    update_mutex.unlock();
  });

  update_thread=std::thread([this](){
    while(!stop_update_thread) {
      std::this_thread::sleep_for(std::chrono::milliseconds(1000));
      update_mutex.lock();
      if(update_paths.size()==0) {
        for(auto it=last_write_times.begin();it!=last_write_times.end();) {
          try {
            if(boost::filesystem::exists(it->first)) { //Added for older boost versions (no exception thrown)
              if(it->second.second<boost::filesystem::last_write_time(it->first)) {
                update_paths.emplace_back(it->first);
              }
              it++;
            }
            else
              it=last_write_times.erase(it);
          }
          catch(const std::exception &e) {
            it=last_write_times.erase(it);
          }
        }
        if(update_paths.size()>0)
          update_dispatcher();
      }
      update_mutex.unlock();
    }
  });
}

Directories::~Directories() {
  stop_update_thread=true;
  update_thread.join();
}

void Directories::open(const boost::filesystem::path& dir_path) {
  if(dir_path=="")
    return;

  INFO("Open folder");

  tree_store->clear();
  update_mutex.lock();
  last_write_times.clear();
  update_paths.clear();
  update_mutex.unlock();

  cmake=std::unique_ptr<CMake>(new CMake(dir_path));
  auto project=cmake->get_functions_parameters("project");
  if(project.size()>0 && project[0].second.size()>0)
    tree_view.get_column(0)->set_title(project[0].second[0]);
  else
    tree_view.get_column(0)->set_title("");
  update_mutex.lock();
  add_path(dir_path, Gtk::TreeModel::Row());
  update_mutex.unlock();

  current_path=dir_path;

  DEBUG("Folder opened");
}

void Directories::update() {
  update_mutex.lock();
  for(auto &last_write_time: last_write_times) {
    add_path(last_write_time.first, last_write_time.second.first);
  }
  update_mutex.unlock();
}

void Directories::select(const boost::filesystem::path &path) {
  if(current_path=="")
    return;

  if(path.string().substr(0, current_path.string().size())!=current_path.string())
    return;

  std::list<boost::filesystem::path> paths;
  boost::filesystem::path parent_path;
  if(boost::filesystem::is_directory(path))
    parent_path=path;
  else
    parent_path=path.parent_path();
  paths.emplace_front(parent_path);
  while(parent_path!=current_path) {
    parent_path=parent_path.parent_path();
    paths.emplace_front(parent_path);
  }

  for(auto &a_path: paths) {
    tree_store->foreach_iter([this, &a_path](const Gtk::TreeModel::iterator& iter){
      if(iter->get_value(column_record.path)==a_path.string()) {
        update_mutex.lock();
        add_path(a_path, *iter);
        update_mutex.unlock();
        return true;
      }
      return false;
    });
  }

  tree_store->foreach_iter([this, &path](const Gtk::TreeModel::iterator& iter){
    if(iter->get_value(column_record.path)==path.string()) {
      auto tree_path=Gtk::TreePath(iter);
      tree_view.expand_to_path(tree_path);
      tree_view.set_cursor(tree_path);
      return true;
    }
    return false;
  });
}

bool Directories::ignored(std::string path) {
  DEBUG("Checking if file-/directory is filtered");
  std::transform(path.begin(), path.end(), path.begin(), ::tolower);

  for(std::string &i : Singleton::Config::directories()->exceptions) {
    if(i == path)
      return false;
  }
  for(auto &i : Singleton::Config::directories()->ignored) {
    if(path.find(i, 0) != std::string::npos)
      return true;
  }

  return false;
}

void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent) {
  last_write_times[dir_path.string()]={parent, boost::filesystem::last_write_time(dir_path)};
  std::unique_ptr<Gtk::TreeNodeChildren> children; //Gtk::TreeNodeChildren is missing default constructor...
  if(parent)
    children=std::unique_ptr<Gtk::TreeNodeChildren>(new Gtk::TreeNodeChildren(parent.children()));
  else
    children=std::unique_ptr<Gtk::TreeNodeChildren>(new Gtk::TreeNodeChildren(tree_store->children()));
  if(*children) {
    if(children->begin()->get_value(column_record.path)=="")
      tree_store->erase(children->begin());
  }
  std::unordered_set<std::string> not_deleted;
  boost::filesystem::directory_iterator end_it;
  for(boost::filesystem::directory_iterator it(dir_path);it!=end_it;it++) {
    auto filename=it->path().filename().string();
    if (!ignored(filename)) {
      bool already_added=false;
      if(*children) {
        for(auto &child: *children) {
          if(child.get_value(column_record.name)==filename) {
            not_deleted.emplace(filename);
            already_added=true;
            break;
          }
        }
      }
      if(!already_added) {
        auto child = tree_store->append(*children);
        not_deleted.emplace(filename);
        child->set_value(column_record.name, filename);
        child->set_value(column_record.path, it->path().string());
        if (boost::filesystem::is_directory(*it)) {
          child->set_value(column_record.id, "a"+filename);
          auto grandchild=tree_store->append(child->children());
          grandchild->set_value(column_record.name, std::string("(empty)"));
        }
        else
          child->set_value(column_record.id, "b"+filename);
      }
    }
  }
  if(*children) {
    for(auto it=children->begin();it!=children->end();) {
      if(not_deleted.count(it->get_value(column_record.name))==0) {
        it=tree_store->erase(it);
      }
      else
        it++;
    }
  }
  if(!*children) {
    auto child=tree_store->append(*children);
    child->set_value(column_record.name, std::string("(empty)"));
  }
}
<commit_msg>Added search to directories.<commit_after>#include "directories.h"
#include "sourcefile.h"
#include "logging.h"
#include "singletons.h"
#include <algorithm>
#include <unordered_set>

#include <iostream> //TODO: remove
using namespace std; //TODO: remove

namespace sigc {
  SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
}

Directories::Directories() : stop_update_thread(false) {
  DEBUG("adding treeview to scrolledwindow");
  add(tree_view);
  set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  tree_store = Gtk::TreeStore::create(column_record);
  tree_view.set_model(tree_store);
  tree_view.append_column("", column_record.name);
  tree_store->set_sort_column(column_record.id, Gtk::SortType::SORT_ASCENDING);
  tree_view.set_enable_search(true); //TODO: why does this not work in OS X?
  tree_view.set_search_column(column_record.name);

  tree_view.signal_row_activated().connect([this](const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column){
    INFO("Directory navigation");
    auto iter = tree_store->get_iter(path);
    if (iter) {
      auto path_str=iter->get_value(column_record.path);
      if(path_str!="") {
        if (boost::filesystem::is_directory(boost::filesystem::path(path_str))) {
          tree_view.row_expanded(path) ? tree_view.collapse_row(path) : tree_view.expand_row(path, false);
        } else {
          if(on_row_activated)
            on_row_activated(path_str);
        }
      }
    }
  });

  tree_view.signal_test_expand_row().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){
    if(iter->children().begin()->get_value(column_record.path)=="") {
      update_mutex.lock();
      add_path(iter->get_value(column_record.path), *iter);
      update_mutex.unlock();
    }
    return false;
  });
  tree_view.signal_row_collapsed().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){
    update_mutex.lock();
    last_write_times.erase(iter->get_value(column_record.path));
    update_mutex.unlock();
    auto children=iter->children();
    if(children) {
      while(children) {
        tree_store->erase(children.begin());
      }
      auto child=tree_store->append(iter->children());
      child->set_value(column_record.name, std::string("(empty)"));
    }
  });

  update_dispatcher.connect([this](){
    update_mutex.lock();
    for(auto &path: update_paths) {
      if(last_write_times.count(path)>0)
        add_path(path, last_write_times.at(path).first);
    }
    update_paths.clear();
    update_mutex.unlock();
  });

  update_thread=std::thread([this](){
    while(!stop_update_thread) {
      std::this_thread::sleep_for(std::chrono::milliseconds(1000));
      update_mutex.lock();
      if(update_paths.size()==0) {
        for(auto it=last_write_times.begin();it!=last_write_times.end();) {
          try {
            if(boost::filesystem::exists(it->first)) { //Added for older boost versions (no exception thrown)
              if(it->second.second<boost::filesystem::last_write_time(it->first)) {
                update_paths.emplace_back(it->first);
              }
              it++;
            }
            else
              it=last_write_times.erase(it);
          }
          catch(const std::exception &e) {
            it=last_write_times.erase(it);
          }
        }
        if(update_paths.size()>0)
          update_dispatcher();
      }
      update_mutex.unlock();
    }
  });
}

Directories::~Directories() {
  stop_update_thread=true;
  update_thread.join();
}

void Directories::open(const boost::filesystem::path& dir_path) {
  if(dir_path=="")
    return;

  INFO("Open folder");

  tree_store->clear();
  update_mutex.lock();
  last_write_times.clear();
  update_paths.clear();
  update_mutex.unlock();

  cmake=std::unique_ptr<CMake>(new CMake(dir_path));
  auto project=cmake->get_functions_parameters("project");
  if(project.size()>0 && project[0].second.size()>0)
    tree_view.get_column(0)->set_title(project[0].second[0]);
  else
    tree_view.get_column(0)->set_title("");
  update_mutex.lock();
  add_path(dir_path, Gtk::TreeModel::Row());
  update_mutex.unlock();

  current_path=dir_path;

  DEBUG("Folder opened");
}

void Directories::update() {
  update_mutex.lock();
  for(auto &last_write_time: last_write_times) {
    add_path(last_write_time.first, last_write_time.second.first);
  }
  update_mutex.unlock();
}

void Directories::select(const boost::filesystem::path &path) {
  if(current_path=="")
    return;

  if(path.string().substr(0, current_path.string().size())!=current_path.string())
    return;

  std::list<boost::filesystem::path> paths;
  boost::filesystem::path parent_path;
  if(boost::filesystem::is_directory(path))
    parent_path=path;
  else
    parent_path=path.parent_path();
  paths.emplace_front(parent_path);
  while(parent_path!=current_path) {
    parent_path=parent_path.parent_path();
    paths.emplace_front(parent_path);
  }

  for(auto &a_path: paths) {
    tree_store->foreach_iter([this, &a_path](const Gtk::TreeModel::iterator& iter){
      if(iter->get_value(column_record.path)==a_path.string()) {
        update_mutex.lock();
        add_path(a_path, *iter);
        update_mutex.unlock();
        return true;
      }
      return false;
    });
  }

  tree_store->foreach_iter([this, &path](const Gtk::TreeModel::iterator& iter){
    if(iter->get_value(column_record.path)==path.string()) {
      auto tree_path=Gtk::TreePath(iter);
      tree_view.expand_to_path(tree_path);
      tree_view.set_cursor(tree_path);
      return true;
    }
    return false;
  });
}

bool Directories::ignored(std::string path) {
  DEBUG("Checking if file-/directory is filtered");
  std::transform(path.begin(), path.end(), path.begin(), ::tolower);

  for(std::string &i : Singleton::Config::directories()->exceptions) {
    if(i == path)
      return false;
  }
  for(auto &i : Singleton::Config::directories()->ignored) {
    if(path.find(i, 0) != std::string::npos)
      return true;
  }

  return false;
}

void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent) {
  last_write_times[dir_path.string()]={parent, boost::filesystem::last_write_time(dir_path)};
  std::unique_ptr<Gtk::TreeNodeChildren> children; //Gtk::TreeNodeChildren is missing default constructor...
  if(parent)
    children=std::unique_ptr<Gtk::TreeNodeChildren>(new Gtk::TreeNodeChildren(parent.children()));
  else
    children=std::unique_ptr<Gtk::TreeNodeChildren>(new Gtk::TreeNodeChildren(tree_store->children()));
  if(*children) {
    if(children->begin()->get_value(column_record.path)=="")
      tree_store->erase(children->begin());
  }
  std::unordered_set<std::string> not_deleted;
  boost::filesystem::directory_iterator end_it;
  for(boost::filesystem::directory_iterator it(dir_path);it!=end_it;it++) {
    auto filename=it->path().filename().string();
    if (!ignored(filename)) {
      bool already_added=false;
      if(*children) {
        for(auto &child: *children) {
          if(child.get_value(column_record.name)==filename) {
            not_deleted.emplace(filename);
            already_added=true;
            break;
          }
        }
      }
      if(!already_added) {
        auto child = tree_store->append(*children);
        not_deleted.emplace(filename);
        child->set_value(column_record.name, filename);
        child->set_value(column_record.path, it->path().string());
        if (boost::filesystem::is_directory(*it)) {
          child->set_value(column_record.id, "a"+filename);
          auto grandchild=tree_store->append(child->children());
          grandchild->set_value(column_record.name, std::string("(empty)"));
        }
        else
          child->set_value(column_record.id, "b"+filename);
      }
    }
  }
  if(*children) {
    for(auto it=children->begin();it!=children->end();) {
      if(not_deleted.count(it->get_value(column_record.name))==0) {
        it=tree_store->erase(it);
      }
      else
        it++;
    }
  }
  if(!*children) {
    auto child=tree_store->append(*children);
    child->set_value(column_record.name, std::string("(empty)"));
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ConnectionFifo.h"

#include <chrono>

#include <folly/Range.h>

namespace facebook {
namespace memcache {

namespace {

uint64_t timeSinceEpoch() {
  using namespace std::chrono;
  return duration_cast<microseconds>(steady_clock::now().time_since_epoch())
      .count();
}

class PipeIov {
 public:
  const iovec* iov() const {
    return iov_;
  }
  size_t size() const {
    return index_;
  }
  bool full() const {
    return index_ >= kMaxLen || remSize_ == 0;
  }

  void reset() {
    index_ = 0;
    remSize_ = PIPE_BUF;
  }
  size_t append(void* buf, size_t len) {
    assert(!full());

    size_t numBytes = std::min(len, remSize_);
    iov_[index_].iov_base = buf;
    iov_[index_].iov_len = numBytes;
    remSize_ -= numBytes;
    ++index_;
    return numBytes;
  }

 private:
  static constexpr size_t kMaxLen = 16;
  iovec iov_[kMaxLen];
  size_t index_ = 0;
  size_t remSize_ = PIPE_BUF;

  static_assert(
      IOV_MAX >= kMaxLen,
      "IOV_MAX must be larger than PipeIov::kMaxLen.");
};

/**
 * Helper to keep state of iteration over const iovec.
 */
class IovecIterator {
 public:
  IovecIterator(const struct iovec* iov, size_t iovcnt)
      : iov_(iov), iovcnt_(iovcnt) {
    assert(iovcnt > 0);

    curBuf_ = reinterpret_cast<char*>(iov_[0].iov_base);
    curBufLen_ = iov_[0].iov_len;
  }

  char* currentBuffer() const {
    return curBuf_;
  }
  size_t currentBufferLength() const {
    return curBufLen_;
  }
  bool hasData() const {
    return index_ < iovcnt_;
  }

  void advance(size_t bytes) {
    assert(hasData());
    assert(bytes <= curBufLen_);

    if (bytes < curBufLen_) {
      curBuf_ += bytes;
      curBufLen_ -= bytes;
    } else { // (bytes == bufLen)
      ++index_;
      if (hasData()) {
        curBuf_ = reinterpret_cast<char*>(iov_[index_].iov_base);
        curBufLen_ = iov_[index_].iov_len;
      }
    }
  }

 private:
  const struct iovec* iov_;
  const size_t iovcnt_;

  size_t index_{0};
  char* curBuf_{nullptr};
  size_t curBufLen_{0};
};

MessageHeader buildMsgHeader(
    const folly::AsyncTransportWrapper* transport,
    folly::StringPiece routerName) {
  MessageHeader header;
  header.setConnectionId(reinterpret_cast<uintptr_t>(transport));

  if (!transport) {
    return header;
  }

  try {
    folly::SocketAddress address;

    transport->getPeerAddress(&address);
    if (address.getFamily() == AF_INET || address.getFamily() == AF_INET6) {
      address.getAddressStr(
          header.peerAddressModifiable(), MessageHeader::kAddressMaxSize);
      header.setPeerPort(address.getPort());
    } else if (address.getFamily() == AF_UNIX) {
      // For unix sockets, just localAddress has the path.
      transport->getLocalAddress(&address);
      std::snprintf(
          header.peerAddressModifiable(),
          MessageHeader::kAddressMaxSize,
          "%s%s",
          kUnixSocketPrefix.data(),
          address.getPath().c_str());
    }

    transport->getLocalAddress(&address);
    header.setLocalPort(address.getPort());
  } catch (const std::exception& e) {
    VLOG(2) << "Error getting host/port to write to debug fifo: " << e.what();
  }

  // set router name
  header.routerNameModifiable()[0] = '\0';
  if (!routerName.empty()) {
    int res = std::snprintf(
        header.routerNameModifiable(),
        MessageHeader::kRouterNameMaxSize,
        "%s",
        routerName.str().c_str());
    if (res < 0) {
      LOG(ERROR) << "Error writing router name '" << routerName
                 << "' to debug fifo";
    }
  }

  return header;
}

} // anonymous namespace

ConnectionFifo::ConnectionFifo() noexcept {}

ConnectionFifo::ConnectionFifo(
    std::shared_ptr<Fifo> debugFifo,
    const folly::AsyncTransportWrapper* transport,
    folly::StringPiece routerName) noexcept
    : debugFifo_(std::move(debugFifo)),
      currentMessageHeader_(buildMsgHeader(transport, routerName)) {}

bool ConnectionFifo::isConnected() const noexcept {
  return debugFifo_ && debugFifo_->isConnected();
}

bool ConnectionFifo::startMessage(
    MessageDirection direction,
    uint32_t typeId) noexcept {
  if (!isConnected()) {
    return false;
  }
  currentMessageHeader_.setDirection(direction);
  currentMessageHeader_.setTypeId(typeId);
  currentMessageHeader_.setTimeUs(timeSinceEpoch());
  nextPacketId_ = 0;
  return true;
}

bool ConnectionFifo::writeData(const void* buf, size_t len) noexcept {
  if (!isConnected()) {
    return false;
  }
  iovec iov[1];
  iov[0].iov_base = const_cast<void*>(buf);
  iov[0].iov_len = len;
  return writeData(iov, 1);
}
bool ConnectionFifo::writeData(
    const struct iovec* iov,
    size_t iovcnt) noexcept {
  // This method breaks data into packets and write them to the FIFO in a
  // specific format, described bellow:
  //  - First, the MessageHeader is written, with the following data formatted
  //    in little endian. The order is exactly as stated bellow:
  //      - magic           - Magic bytes to identify that this is a message
  //                          header. Value: 0xfaceb00c
  //      - version         - Version of the protocol.
  //      - peer ipAddress  - char[40] containing a 0-terminated string
  //                          representation of the peer's ip address.
  //      - peer port       - Peer port used for communication.
  //      - connection id   - Id of the connection that this message belongs to.
  //      - local port      - Local port used for communication.
  //      - direction       - Direction of the message (sent or received).
  //      - type id         - Id of the type of the request. For requests,
  //                          it's always odd, for responses it's reqTypeId + 1.
  //      - time            - Time in micros since epoch of when the message
  //                          originated.
  //  - After the message header, the data of the message is divided in
  //    packets of at most PIPE_BUF bytes.
  //  - Each packet is composed of two parts: header and body.
  //    - The packet header contains the following metadata about the packet:
  //      - connection id   - the id of the connection the packet belogs to.
  //                          8 bytes, little endian.
  //      - packet id       - Incremental id of the packet, starting at 0.
  //                          2 bytes, little endian.
  //      - packet size     - The size of the body of the packet.
  //                          2 bytes, little endian.
  //    - The body is the data itself (i.e. contents of iov).
  //  - Each packet is atomically written to the pipe. That means that
  //    the entire packet (header and body) will appear together in the
  //    pipe, as expected. The various packets of a message might be
  //    interleaved with packets from another message.
  //  - The entire message is NOT guaranteed to be written. Even though each
  //    packet is either completely written or not present at all, the message
  //    transmission might be interrupted - meaning that the last packets might
  //    be missing.
  //
  // Here is the layout of a message:
  // ---------------------------------------------------------
  // | MESSAGE HEADER | PACKET 1 | PACKET 2 | ... | PACKET N |
  // ---------------------------------------------------------
  // Where each packet has the following format:
  // -------------------------------
  // | PACKET HEADER | PACKET BODY |
  // -------------------------------

  if (!isConnected() || iovcnt == 0) {
    return false;
  }

  PipeIov pipeIov;
  IovecIterator iovIter(iov, iovcnt);

  // Write header only if this is a brand new message.
  if (nextPacketId_ == 0) {
    pipeIov.append(&currentMessageHeader_, sizeof(MessageHeader));
  }

  // Create packet header
  PacketHeader pkgHeader;
  pkgHeader.setConnectionId(currentMessageHeader_.connectionId());

  // Add packet header
  pipeIov.append(&pkgHeader, sizeof(PacketHeader));

  // Send data
  uint32_t packetSize = 0;
  while (iovIter.hasData()) {
    // Build pipeIov
    while (iovIter.hasData() && !pipeIov.full()) {
      auto bytesAppended = pipeIov.append(
          iovIter.currentBuffer(), iovIter.currentBufferLength());
      iovIter.advance(bytesAppended);
      packetSize += bytesAppended;
    }
    pkgHeader.setPacketSize(packetSize);
    pkgHeader.setPacketId(nextPacketId_);

    // Write to pipe
    if (!debugFifo_->write(pipeIov.iov(), pipeIov.size())) {
      return false;
    }

    ++nextPacketId_;
    packetSize = 0;
    pipeIov.reset();
    pipeIov.append(&pkgHeader, sizeof(PacketHeader));
  }

  return true;
}

} // namespace memcache
} // namespace facebook
<commit_msg>Fix error setting transport local address in debug fifos when using Unix socket listeners (#388)<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ConnectionFifo.h"

#include <chrono>

#include <folly/Range.h>

namespace facebook {
namespace memcache {

namespace {

uint64_t timeSinceEpoch() {
  using namespace std::chrono;
  return duration_cast<microseconds>(steady_clock::now().time_since_epoch())
      .count();
}

class PipeIov {
 public:
  const iovec* iov() const {
    return iov_;
  }
  size_t size() const {
    return index_;
  }
  bool full() const {
    return index_ >= kMaxLen || remSize_ == 0;
  }

  void reset() {
    index_ = 0;
    remSize_ = PIPE_BUF;
  }
  size_t append(void* buf, size_t len) {
    assert(!full());

    size_t numBytes = std::min(len, remSize_);
    iov_[index_].iov_base = buf;
    iov_[index_].iov_len = numBytes;
    remSize_ -= numBytes;
    ++index_;
    return numBytes;
  }

 private:
  static constexpr size_t kMaxLen = 16;
  iovec iov_[kMaxLen];
  size_t index_ = 0;
  size_t remSize_ = PIPE_BUF;

  static_assert(
      IOV_MAX >= kMaxLen,
      "IOV_MAX must be larger than PipeIov::kMaxLen.");
};

/**
 * Helper to keep state of iteration over const iovec.
 */
class IovecIterator {
 public:
  IovecIterator(const struct iovec* iov, size_t iovcnt)
      : iov_(iov), iovcnt_(iovcnt) {
    assert(iovcnt > 0);

    curBuf_ = reinterpret_cast<char*>(iov_[0].iov_base);
    curBufLen_ = iov_[0].iov_len;
  }

  char* currentBuffer() const {
    return curBuf_;
  }
  size_t currentBufferLength() const {
    return curBufLen_;
  }
  bool hasData() const {
    return index_ < iovcnt_;
  }

  void advance(size_t bytes) {
    assert(hasData());
    assert(bytes <= curBufLen_);

    if (bytes < curBufLen_) {
      curBuf_ += bytes;
      curBufLen_ -= bytes;
    } else { // (bytes == bufLen)
      ++index_;
      if (hasData()) {
        curBuf_ = reinterpret_cast<char*>(iov_[index_].iov_base);
        curBufLen_ = iov_[index_].iov_len;
      }
    }
  }

 private:
  const struct iovec* iov_;
  const size_t iovcnt_;

  size_t index_{0};
  char* curBuf_{nullptr};
  size_t curBufLen_{0};
};

MessageHeader buildMsgHeader(
    const folly::AsyncTransportWrapper* transport,
    folly::StringPiece routerName) {
  MessageHeader header;
  header.setConnectionId(reinterpret_cast<uintptr_t>(transport));

  if (!transport) {
    return header;
  }

  try {
    folly::SocketAddress address;

    transport->getPeerAddress(&address);
    if (address.getFamily() == AF_INET || address.getFamily() == AF_INET6) {
      address.getAddressStr(
          header.peerAddressModifiable(), MessageHeader::kAddressMaxSize);
      header.setPeerPort(address.getPort());
      header.setLocalPort(address.getPort());
    } else if (address.getFamily() == AF_UNIX) {
      // For unix sockets, just localAddress has the path.
      transport->getLocalAddress(&address);
      std::snprintf(
          header.peerAddressModifiable(),
          MessageHeader::kAddressMaxSize,
          "%s%s",
          kUnixSocketPrefix.data(),
          address.getPath().c_str());
    }

    transport->getLocalAddress(&address);
  } catch (const std::exception& e) {
    VLOG(2) << "Error getting host/port to write to debug fifo: " << e.what();
  }

  // set router name
  header.routerNameModifiable()[0] = '\0';
  if (!routerName.empty()) {
    int res = std::snprintf(
        header.routerNameModifiable(),
        MessageHeader::kRouterNameMaxSize,
        "%s",
        routerName.str().c_str());
    if (res < 0) {
      LOG(ERROR) << "Error writing router name '" << routerName
                 << "' to debug fifo";
    }
  }

  return header;
}

} // anonymous namespace

ConnectionFifo::ConnectionFifo() noexcept {}

ConnectionFifo::ConnectionFifo(
    std::shared_ptr<Fifo> debugFifo,
    const folly::AsyncTransportWrapper* transport,
    folly::StringPiece routerName) noexcept
    : debugFifo_(std::move(debugFifo)),
      currentMessageHeader_(buildMsgHeader(transport, routerName)) {}

bool ConnectionFifo::isConnected() const noexcept {
  return debugFifo_ && debugFifo_->isConnected();
}

bool ConnectionFifo::startMessage(
    MessageDirection direction,
    uint32_t typeId) noexcept {
  if (!isConnected()) {
    return false;
  }
  currentMessageHeader_.setDirection(direction);
  currentMessageHeader_.setTypeId(typeId);
  currentMessageHeader_.setTimeUs(timeSinceEpoch());
  nextPacketId_ = 0;
  return true;
}

bool ConnectionFifo::writeData(const void* buf, size_t len) noexcept {
  if (!isConnected()) {
    return false;
  }
  iovec iov[1];
  iov[0].iov_base = const_cast<void*>(buf);
  iov[0].iov_len = len;
  return writeData(iov, 1);
}
bool ConnectionFifo::writeData(
    const struct iovec* iov,
    size_t iovcnt) noexcept {
  // This method breaks data into packets and write them to the FIFO in a
  // specific format, described bellow:
  //  - First, the MessageHeader is written, with the following data formatted
  //    in little endian. The order is exactly as stated bellow:
  //      - magic           - Magic bytes to identify that this is a message
  //                          header. Value: 0xfaceb00c
  //      - version         - Version of the protocol.
  //      - peer ipAddress  - char[40] containing a 0-terminated string
  //                          representation of the peer's ip address.
  //      - peer port       - Peer port used for communication.
  //      - connection id   - Id of the connection that this message belongs to.
  //      - local port      - Local port used for communication.
  //      - direction       - Direction of the message (sent or received).
  //      - type id         - Id of the type of the request. For requests,
  //                          it's always odd, for responses it's reqTypeId + 1.
  //      - time            - Time in micros since epoch of when the message
  //                          originated.
  //  - After the message header, the data of the message is divided in
  //    packets of at most PIPE_BUF bytes.
  //  - Each packet is composed of two parts: header and body.
  //    - The packet header contains the following metadata about the packet:
  //      - connection id   - the id of the connection the packet belogs to.
  //                          8 bytes, little endian.
  //      - packet id       - Incremental id of the packet, starting at 0.
  //                          2 bytes, little endian.
  //      - packet size     - The size of the body of the packet.
  //                          2 bytes, little endian.
  //    - The body is the data itself (i.e. contents of iov).
  //  - Each packet is atomically written to the pipe. That means that
  //    the entire packet (header and body) will appear together in the
  //    pipe, as expected. The various packets of a message might be
  //    interleaved with packets from another message.
  //  - The entire message is NOT guaranteed to be written. Even though each
  //    packet is either completely written or not present at all, the message
  //    transmission might be interrupted - meaning that the last packets might
  //    be missing.
  //
  // Here is the layout of a message:
  // ---------------------------------------------------------
  // | MESSAGE HEADER | PACKET 1 | PACKET 2 | ... | PACKET N |
  // ---------------------------------------------------------
  // Where each packet has the following format:
  // -------------------------------
  // | PACKET HEADER | PACKET BODY |
  // -------------------------------

  if (!isConnected() || iovcnt == 0) {
    return false;
  }

  PipeIov pipeIov;
  IovecIterator iovIter(iov, iovcnt);

  // Write header only if this is a brand new message.
  if (nextPacketId_ == 0) {
    pipeIov.append(&currentMessageHeader_, sizeof(MessageHeader));
  }

  // Create packet header
  PacketHeader pkgHeader;
  pkgHeader.setConnectionId(currentMessageHeader_.connectionId());

  // Add packet header
  pipeIov.append(&pkgHeader, sizeof(PacketHeader));

  // Send data
  uint32_t packetSize = 0;
  while (iovIter.hasData()) {
    // Build pipeIov
    while (iovIter.hasData() && !pipeIov.full()) {
      auto bytesAppended = pipeIov.append(
          iovIter.currentBuffer(), iovIter.currentBufferLength());
      iovIter.advance(bytesAppended);
      packetSize += bytesAppended;
    }
    pkgHeader.setPacketSize(packetSize);
    pkgHeader.setPacketId(nextPacketId_);

    // Write to pipe
    if (!debugFifo_->write(pipeIov.iov(), pipeIov.size())) {
      return false;
    }

    ++nextPacketId_;
    packetSize = 0;
    pipeIov.reset();
    pipeIov.append(&pkgHeader, sizeof(PacketHeader));
  }

  return true;
}

} // namespace memcache
} // namespace facebook
<|endoftext|>