<commit_before>/*
 * Copyright (C) 2016 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stack>
#include <boost/range/algorithm/heap_algorithm.hpp>
#include <seastar/util/defer.hh>

#include "mutation.hh"
#include "streamed_mutation.hh"
#include "utils/move.hh"

mutation_fragment::mutation_fragment(static_row&& r)
    : _kind(kind::static_row), _data(std::make_unique<data>())
{
    new (&_data->_static_row) static_row(std::move(r));
}

mutation_fragment::mutation_fragment(clustering_row&& r)
    : _kind(kind::clustering_row), _data(std::make_unique<data>())
{
    new (&_data->_clustering_row) clustering_row(std::move(r));
}

mutation_fragment::mutation_fragment(range_tombstone&& r)
    : _kind(kind::range_tombstone), _data(std::make_unique<data>())
{
    new (&_data->_range_tombstone) range_tombstone(std::move(r));
}

void mutation_fragment::destroy_data() noexcept
{
    switch (_kind) {
    case kind::static_row:
        _data->_static_row.~static_row();
        break;
    case kind::clustering_row:
        _data->_clustering_row.~clustering_row();
        break;
    case kind::range_tombstone:
        _data->_range_tombstone.~range_tombstone();
        break;
    }
}

const clustering_key_prefix& mutation_fragment::key() const
{
    assert(has_key());
    struct get_key_visitor {
        const clustering_key_prefix& operator()(const clustering_row& cr) { return cr.key(); }
        const clustering_key_prefix& operator()(const range_tombstone& rt) { return rt.start; }
        const clustering_key_prefix& operator()(...) { abort(); }
    };
    return visit(get_key_visitor());
}

void mutation_fragment::apply(const schema& s, mutation_fragment&& mf)
{
    assert(_kind == mf._kind);
    assert(!is_range_tombstone());
    switch (_kind) {
    case kind::static_row:
        _data->_static_row.apply(s, std::move(mf._data->_static_row));
        mf._data->_static_row.~static_row();
        break;
    case kind::clustering_row:
        _data->_clustering_row.apply(s, std::move(mf._data->_clustering_row));
        mf._data->_clustering_row.~clustering_row();
        break;
    default: abort();
    }
    mf._data.reset();
}

position_in_partition_view mutation_fragment::position() const
{
    return visit([] (auto& mf) { return mf.position(); });
}

std::ostream& operator<<(std::ostream& os, const streamed_mutation& sm) {
    auto& s = *sm.schema();
    fprint(os, "{%s.%s key %s streamed mutation}", s.ks_name(), s.cf_name(), sm.decorated_key());
    return os;
}

std::ostream& operator<<(std::ostream& os, mutation_fragment::kind k)
{
    switch (k) {
    case mutation_fragment::kind::static_row: return os << "static row";
    case mutation_fragment::kind::clustering_row: return os << "clustering row";
    case mutation_fragment::kind::range_tombstone: return os << "range tombstone";
    }
    abort();
}

streamed_mutation streamed_mutation_from_mutation(mutation m)
{
    class reader final : public streamed_mutation::impl {
        mutation _mutation;
        position_in_partition::less_compare _cmp;
        bool _static_row_done = false;
        mutation_fragment_opt _rt;
        mutation_fragment_opt _cr;
    private:
        void prepare_next_clustering_row() {
            auto& crs = _mutation.partition().clustered_rows();
            auto re = crs.unlink_leftmost_without_rebalance();
            if (re) {
                auto re_deleter = defer([re] { current_deleter<rows_entry>()(re); });
                _cr = mutation_fragment(std::move(*re));
            }
        }
        void prepare_next_range_tombstone() {
            auto& rts = _mutation.partition().row_tombstones().tombstones();
            auto rt = rts.unlink_leftmost_without_rebalance();
            if (rt) {
                auto rt_deleter = defer([rt] { current_deleter<range_tombstone>()(rt); });
                _rt = mutation_fragment(std::move(*rt));
            }
        }
        mutation_fragment_opt read_next() {
            if (_cr && (!_rt || _cmp(_cr->position(), _rt->position()))) {
                auto cr = move_and_disengage(_cr);
                prepare_next_clustering_row();
                return cr;
            } else if (_rt) {
                auto rt = move_and_disengage(_rt);
                prepare_next_range_tombstone();
                return rt;
            }
            return { };
        }
    private:
        void do_fill_buffer() {
            if (!_static_row_done) {
                _static_row_done = true;
                if (!_mutation.partition().static_row().empty()) {
                    push_mutation_fragment(static_row(std::move(_mutation.partition().static_row())));
                }
            }
            while (!is_end_of_stream() && !is_buffer_full()) {
                auto mfopt = read_next();
                if (mfopt) {
                    push_mutation_fragment(std::move(*mfopt));
                } else {
                    _end_of_stream = true;
                }
            }
        }
    public:
        explicit reader(mutation m)
            : streamed_mutation::impl(m.schema(), m.decorated_key(), m.partition().partition_tombstone())
            , _mutation(std::move(m))
            , _cmp(*_mutation.schema())
        {
            auto mutation_destroyer = defer([this] { destroy_mutation(); });

            prepare_next_clustering_row();
            prepare_next_range_tombstone();

            do_fill_buffer();

            mutation_destroyer.cancel();
        }

        void destroy_mutation() noexcept {
            // After unlink_leftmost_without_rebalance() was called on a bi::set
            // we need to complete destroying the tree using that function.
            // clear_and_dispose() used by mutation_partition destructor won't
            // work properly.

            auto& crs = _mutation.partition().clustered_rows();
            auto re = crs.unlink_leftmost_without_rebalance();
            while (re) {
                current_deleter<rows_entry>()(re);
                re = crs.unlink_leftmost_without_rebalance();
            }

            auto& rts = _mutation.partition().row_tombstones().tombstones();
            auto rt = rts.unlink_leftmost_without_rebalance();
            while (rt) {
                current_deleter<range_tombstone>()(rt);
                rt = rts.unlink_leftmost_without_rebalance();
            }
        }

        ~reader() {
            destroy_mutation();
        }

        virtual future<> fill_buffer() override {
            do_fill_buffer();
            return make_ready_future<>();
        }
    };

    return make_streamed_mutation<reader>(std::move(m));
}

class mutation_merger final : public streamed_mutation::impl {
    std::vector<streamed_mutation> _original_readers;
    std::vector<streamed_mutation*> _next_readers;
    // FIXME: do not store all in-flight clustering rows in memory
    struct row_and_reader {
        mutation_fragment row;
        streamed_mutation* reader;
    };
    std::vector<row_and_reader> _readers;
    range_tombstone_stream _deferred_tombstones;
private:
    void read_next() {
        if (_readers.empty()) {
            _end_of_stream = true;
            return;
        }

        position_in_partition::less_compare cmp(*_schema);
        auto heap_compare = [&] (auto& a, auto& b) { return cmp(b.row.position(), a.row.position()); };

        auto result = [&] {
            auto rt = _deferred_tombstones.get_next(_readers.front().row);
            if (rt) {
                return std::move(*rt);
            }
            boost::range::pop_heap(_readers, heap_compare);
            auto mf = std::move(_readers.back().row);
            _next_readers.emplace_back(std::move(_readers.back().reader));
            _readers.pop_back();
            return std::move(mf);
        }();

        while (!_readers.empty()) {
            if (cmp(result.position(), _readers.front().row.position())) {
                break;
            }
            boost::range::pop_heap(_readers, heap_compare);
            if (result.is_range_tombstone()) {
                auto remainder = result.as_range_tombstone().apply(*_schema, std::move(_readers.back().row.as_range_tombstone()));
                if (remainder) {
                    _deferred_tombstones.apply(std::move(*remainder));
                }
            } else {
                result.apply(*_schema, std::move(_readers.back().row));
            }
            _next_readers.emplace_back(std::move(_readers.back().reader));
            _readers.pop_back();
        }

        push_mutation_fragment(std::move(result));
    }

    void do_fill_buffer() {
        position_in_partition::less_compare cmp(*_schema);
        auto heap_compare = [&] (auto& a, auto& b) { return cmp(b.row.position(), a.row.position()); };

        for (auto& rd : _next_readers) {
            if (rd->is_buffer_empty()) {
                assert(rd->is_end_of_stream());
                continue;
            }
            _readers.emplace_back(row_and_reader { rd->pop_mutation_fragment(), std::move(rd) });
            boost::range::push_heap(_readers, heap_compare);
        }
        _next_readers.clear();

        read_next();
    }
    void prefill_buffer() {
        while (!is_end_of_stream() && !is_buffer_full()) {
            for (auto& rd : _next_readers) {
                if (rd->is_buffer_empty() && !rd->is_end_of_stream()) {
                    return;
                }
            }
            do_fill_buffer();
        }
    }

    static tombstone merge_partition_tombstones(const std::vector<streamed_mutation>& readers) {
        tombstone t;
        for (auto& r : readers) {
            t.apply(r.partition_tombstone());
        }
        return t;
    }
protected:
    virtual future<> fill_buffer() override  {
        if (_next_readers.empty()) {
            return make_ready_future<>();
        }
        while (!is_end_of_stream() && !is_buffer_full()) {
            std::vector<future<>> more_data;
            for (auto& rd : _next_readers) {
                if (rd->is_buffer_empty() && !rd->is_end_of_stream()) {
                    more_data.emplace_back(rd->fill_buffer());
                }
            }
            if (!more_data.empty()) {
                return parallel_for_each(std::move(more_data), [] (auto& f) { return std::move(f); }).then([this] { return fill_buffer(); });
            }
            do_fill_buffer();
        }
        return make_ready_future<>();
    }
public:
    mutation_merger(schema_ptr s, dht::decorated_key dk, std::vector<streamed_mutation> readers)
        : streamed_mutation::impl(s, std::move(dk), merge_partition_tombstones(readers))
        , _original_readers(std::move(readers)), _deferred_tombstones(*s)
    {
        _next_readers.reserve(_original_readers.size());
        _readers.reserve(_original_readers.size());
        for (auto& rd : _original_readers) {
            _next_readers.emplace_back(&rd);
        }
        prefill_buffer();
    }
};

streamed_mutation merge_mutations(std::vector<streamed_mutation> ms)
{
    assert(!ms.empty());
    return make_streamed_mutation<mutation_merger>(ms.back().schema(), ms.back().decorated_key(), std::move(ms));
}

mutation_fragment_opt range_tombstone_stream::do_get_next()
{
    auto& rt = *_list.tombstones().begin();
    auto mf = mutation_fragment(std::move(rt));
    _list.tombstones().erase(_list.begin());
    current_deleter<range_tombstone>()(&rt);
    return mf;
}

mutation_fragment_opt range_tombstone_stream::get_next(const rows_entry& re)
{
    if (!_list.empty()) {
        position_in_partition_view view(position_in_partition_view::clustering_row_tag_t(), re.key());
        return !_cmp(view, _list.begin()->position()) ? do_get_next() : mutation_fragment_opt();
    }
    return { };
}

mutation_fragment_opt range_tombstone_stream::get_next(const mutation_fragment& mf)
{
    if (!_list.empty()) {
        return !_cmp(mf.position(), _list.begin()->position()) ? do_get_next() : mutation_fragment_opt();
    }
    return { };
}

mutation_fragment_opt range_tombstone_stream::get_next()
{
    if (!_list.empty()) {
        return do_get_next();
    }
    return { };
}

streamed_mutation reverse_streamed_mutation(streamed_mutation sm) {
    class reversing_steamed_mutation final : public streamed_mutation::impl {
        streamed_mutation_opt _source;
        mutation_fragment_opt _static_row;
        std::stack<mutation_fragment> _mutation_fragments;
    private:
        future<> consume_source() {
            return repeat([&] {
                return (*_source)().then([&] (mutation_fragment_opt mf) {
                    if (!mf) {
                        return stop_iteration::yes;
                    } else if (mf->is_static_row()) {
                        _static_row = std::move(mf);
                    } else {
                        if (mf->is_range_tombstone()) {
                            mf->as_range_tombstone().flip();
                        }
                        _mutation_fragments.emplace(std::move(*mf));
                    }
                    return stop_iteration::no;
                });
            }).then([&] {
                _source = { };
            });
        }
    public:
        explicit reversing_steamed_mutation(streamed_mutation sm)
            : streamed_mutation::impl(sm.schema(), sm.decorated_key(), sm.partition_tombstone())
            , _source(std::move(sm))
        { }

        virtual future<> fill_buffer() override {
            if (_source) {
                return consume_source().then([this] { return fill_buffer(); });
            }
            if (_static_row) {
                push_mutation_fragment(std::move(*_static_row));
                _static_row = { };
            }
            while (!is_end_of_stream() && !is_buffer_full()) {
                if (_mutation_fragments.empty()) {
                    _end_of_stream = true;
                } else {
                    push_mutation_fragment(std::move(_mutation_fragments.top()));
                    _mutation_fragments.pop();
                }
            }
            return make_ready_future<>();
        }
    };

    return make_streamed_mutation<reversing_steamed_mutation>(std::move(sm));
};

<commit_msg>mutation_merger: Emit deferred tombstones<commit_after>/*
 * Copyright (C) 2016 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stack>
#include <boost/range/algorithm/heap_algorithm.hpp>
#include <seastar/util/defer.hh>

#include "mutation.hh"
#include "streamed_mutation.hh"
#include "utils/move.hh"

mutation_fragment::mutation_fragment(static_row&& r)
    : _kind(kind::static_row), _data(std::make_unique<data>())
{
    new (&_data->_static_row) static_row(std::move(r));
}

mutation_fragment::mutation_fragment(clustering_row&& r)
    : _kind(kind::clustering_row), _data(std::make_unique<data>())
{
    new (&_data->_clustering_row) clustering_row(std::move(r));
}

mutation_fragment::mutation_fragment(range_tombstone&& r)
    : _kind(kind::range_tombstone), _data(std::make_unique<data>())
{
    new (&_data->_range_tombstone) range_tombstone(std::move(r));
}

void mutation_fragment::destroy_data() noexcept
{
    switch (_kind) {
    case kind::static_row:
        _data->_static_row.~static_row();
        break;
    case kind::clustering_row:
        _data->_clustering_row.~clustering_row();
        break;
    case kind::range_tombstone:
        _data->_range_tombstone.~range_tombstone();
        break;
    }
}

const clustering_key_prefix& mutation_fragment::key() const
{
    assert(has_key());
    struct get_key_visitor {
        const clustering_key_prefix& operator()(const clustering_row& cr) { return cr.key(); }
        const clustering_key_prefix& operator()(const range_tombstone& rt) { return rt.start; }
        const clustering_key_prefix& operator()(...) { abort(); }
    };
    return visit(get_key_visitor());
}

void mutation_fragment::apply(const schema& s, mutation_fragment&& mf)
{
    assert(_kind == mf._kind);
    assert(!is_range_tombstone());
    switch (_kind) {
    case kind::static_row:
        _data->_static_row.apply(s, std::move(mf._data->_static_row));
        mf._data->_static_row.~static_row();
        break;
    case kind::clustering_row:
        _data->_clustering_row.apply(s, std::move(mf._data->_clustering_row));
        mf._data->_clustering_row.~clustering_row();
        break;
    default: abort();
    }
    mf._data.reset();
}

position_in_partition_view mutation_fragment::position() const
{
    return visit([] (auto& mf) { return mf.position(); });
}

std::ostream& operator<<(std::ostream& os, const streamed_mutation& sm) {
    auto& s = *sm.schema();
    fprint(os, "{%s.%s key %s streamed mutation}", s.ks_name(), s.cf_name(), sm.decorated_key());
    return os;
}

std::ostream& operator<<(std::ostream& os, mutation_fragment::kind k)
{
    switch (k) {
    case mutation_fragment::kind::static_row: return os << "static row";
    case mutation_fragment::kind::clustering_row: return os << "clustering row";
    case mutation_fragment::kind::range_tombstone: return os << "range tombstone";
    }
    abort();
}

streamed_mutation streamed_mutation_from_mutation(mutation m)
{
    class reader final : public streamed_mutation::impl {
        mutation _mutation;
        position_in_partition::less_compare _cmp;
        bool _static_row_done = false;
        mutation_fragment_opt _rt;
        mutation_fragment_opt _cr;
    private:
        void prepare_next_clustering_row() {
            auto& crs = _mutation.partition().clustered_rows();
            auto re = crs.unlink_leftmost_without_rebalance();
            if (re) {
                auto re_deleter = defer([re] { current_deleter<rows_entry>()(re); });
                _cr = mutation_fragment(std::move(*re));
            }
        }
        void prepare_next_range_tombstone() {
            auto& rts = _mutation.partition().row_tombstones().tombstones();
            auto rt = rts.unlink_leftmost_without_rebalance();
            if (rt) {
                auto rt_deleter = defer([rt] { current_deleter<range_tombstone>()(rt); });
                _rt = mutation_fragment(std::move(*rt));
            }
        }
        mutation_fragment_opt read_next() {
            if (_cr && (!_rt || _cmp(_cr->position(), _rt->position()))) {
                auto cr = move_and_disengage(_cr);
                prepare_next_clustering_row();
                return cr;
            } else if (_rt) {
                auto rt = move_and_disengage(_rt);
                prepare_next_range_tombstone();
                return rt;
            }
            return { };
        }
    private:
        void do_fill_buffer() {
            if (!_static_row_done) {
                _static_row_done = true;
                if (!_mutation.partition().static_row().empty()) {
                    push_mutation_fragment(static_row(std::move(_mutation.partition().static_row())));
                }
            }
            while (!is_end_of_stream() && !is_buffer_full()) {
                auto mfopt = read_next();
                if (mfopt) {
                    push_mutation_fragment(std::move(*mfopt));
                } else {
                    _end_of_stream = true;
                }
            }
        }
    public:
        explicit reader(mutation m)
            : streamed_mutation::impl(m.schema(), m.decorated_key(), m.partition().partition_tombstone())
            , _mutation(std::move(m))
            , _cmp(*_mutation.schema())
        {
            auto mutation_destroyer = defer([this] { destroy_mutation(); });

            prepare_next_clustering_row();
            prepare_next_range_tombstone();

            do_fill_buffer();

            mutation_destroyer.cancel();
        }

        void destroy_mutation() noexcept {
            // After unlink_leftmost_without_rebalance() was called on a bi::set
            // we need to complete destroying the tree using that function.
            // clear_and_dispose() used by mutation_partition destructor won't
            // work properly.

            auto& crs = _mutation.partition().clustered_rows();
            auto re = crs.unlink_leftmost_without_rebalance();
            while (re) {
                current_deleter<rows_entry>()(re);
                re = crs.unlink_leftmost_without_rebalance();
            }

            auto& rts = _mutation.partition().row_tombstones().tombstones();
            auto rt = rts.unlink_leftmost_without_rebalance();
            while (rt) {
                current_deleter<range_tombstone>()(rt);
                rt = rts.unlink_leftmost_without_rebalance();
            }
        }

        ~reader() {
            destroy_mutation();
        }

        virtual future<> fill_buffer() override {
            do_fill_buffer();
            return make_ready_future<>();
        }
    };

    return make_streamed_mutation<reader>(std::move(m));
}

class mutation_merger final : public streamed_mutation::impl {
    std::vector<streamed_mutation> _original_readers;
    std::vector<streamed_mutation*> _next_readers;
    // FIXME: do not store all in-flight clustering rows in memory
    struct row_and_reader {
        mutation_fragment row;
        streamed_mutation* reader;
    };
    std::vector<row_and_reader> _readers;
    range_tombstone_stream _deferred_tombstones;
private:
    void read_next() {
        if (_readers.empty()) {
            auto rt = _deferred_tombstones.get_next();
            if (rt) {
                push_mutation_fragment(std::move(*rt));
            } else {
                _end_of_stream = true;
            }
            return;
        }

        position_in_partition::less_compare cmp(*_schema);
        auto heap_compare = [&] (auto& a, auto& b) { return cmp(b.row.position(), a.row.position()); };

        auto result = [&] {
            auto rt = _deferred_tombstones.get_next(_readers.front().row);
            if (rt) {
                return std::move(*rt);
            }
            boost::range::pop_heap(_readers, heap_compare);
            auto mf = std::move(_readers.back().row);
            _next_readers.emplace_back(std::move(_readers.back().reader));
            _readers.pop_back();
            return std::move(mf);
        }();

        while (!_readers.empty()) {
            if (cmp(result.position(), _readers.front().row.position())) {
                break;
            }
            boost::range::pop_heap(_readers, heap_compare);
            if (result.is_range_tombstone()) {
                auto remainder = result.as_range_tombstone().apply(*_schema, std::move(_readers.back().row.as_range_tombstone()));
                if (remainder) {
                    _deferred_tombstones.apply(std::move(*remainder));
                }
            } else {
                result.apply(*_schema, std::move(_readers.back().row));
            }
            _next_readers.emplace_back(std::move(_readers.back().reader));
            _readers.pop_back();
        }

        push_mutation_fragment(std::move(result));
    }

    void do_fill_buffer() {
        position_in_partition::less_compare cmp(*_schema);
        auto heap_compare = [&] (auto& a, auto& b) { return cmp(b.row.position(), a.row.position()); };

        for (auto& rd : _next_readers) {
            if (rd->is_buffer_empty()) {
                assert(rd->is_end_of_stream());
                continue;
            }
            _readers.emplace_back(row_and_reader { rd->pop_mutation_fragment(), std::move(rd) });
            boost::range::push_heap(_readers, heap_compare);
        }
        _next_readers.clear();

        read_next();
    }
    void prefill_buffer() {
        while (!is_end_of_stream() && !is_buffer_full()) {
            for (auto& rd : _next_readers) {
                if (rd->is_buffer_empty() && !rd->is_end_of_stream()) {
                    return;
                }
            }
            do_fill_buffer();
        }
    }

    static tombstone merge_partition_tombstones(const std::vector<streamed_mutation>& readers) {
        tombstone t;
        for (auto& r : readers) {
            t.apply(r.partition_tombstone());
        }
        return t;
    }
protected:
    virtual future<> fill_buffer() override  {
        while (!is_end_of_stream() && !is_buffer_full()) {
            std::vector<future<>> more_data;
            for (auto& rd : _next_readers) {
                if (rd->is_buffer_empty() && !rd->is_end_of_stream()) {
                    more_data.emplace_back(rd->fill_buffer());
                }
            }
            if (!more_data.empty()) {
                return parallel_for_each(std::move(more_data), [] (auto& f) { return std::move(f); }).then([this] { return fill_buffer(); });
            }
            do_fill_buffer();
        }
        return make_ready_future<>();
    }
public:
    mutation_merger(schema_ptr s, dht::decorated_key dk, std::vector<streamed_mutation> readers)
        : streamed_mutation::impl(s, std::move(dk), merge_partition_tombstones(readers))
        , _original_readers(std::move(readers)), _deferred_tombstones(*s)
    {
        _next_readers.reserve(_original_readers.size());
        _readers.reserve(_original_readers.size());
        for (auto& rd : _original_readers) {
            _next_readers.emplace_back(&rd);
        }
        prefill_buffer();
    }
};

streamed_mutation merge_mutations(std::vector<streamed_mutation> ms)
{
    assert(!ms.empty());
    return make_streamed_mutation<mutation_merger>(ms.back().schema(), ms.back().decorated_key(), std::move(ms));
}

mutation_fragment_opt range_tombstone_stream::do_get_next()
{
    auto& rt = *_list.tombstones().begin();
    auto mf = mutation_fragment(std::move(rt));
    _list.tombstones().erase(_list.begin());
    current_deleter<range_tombstone>()(&rt);
    return mf;
}

mutation_fragment_opt range_tombstone_stream::get_next(const rows_entry& re)
{
    if (!_list.empty()) {
        position_in_partition_view view(position_in_partition_view::clustering_row_tag_t(), re.key());
        return !_cmp(view, _list.begin()->position()) ? do_get_next() : mutation_fragment_opt();
    }
    return { };
}

mutation_fragment_opt range_tombstone_stream::get_next(const mutation_fragment& mf)
{
    if (!_list.empty()) {
        return !_cmp(mf.position(), _list.begin()->position()) ? do_get_next() : mutation_fragment_opt();
    }
    return { };
}

mutation_fragment_opt range_tombstone_stream::get_next()
{
    if (!_list.empty()) {
        return do_get_next();
    }
    return { };
}

streamed_mutation reverse_streamed_mutation(streamed_mutation sm) {
    class reversing_steamed_mutation final : public streamed_mutation::impl {
        streamed_mutation_opt _source;
        mutation_fragment_opt _static_row;
        std::stack<mutation_fragment> _mutation_fragments;
    private:
        future<> consume_source() {
            return repeat([&] {
                return (*_source)().then([&] (mutation_fragment_opt mf) {
                    if (!mf) {
                        return stop_iteration::yes;
                    } else if (mf->is_static_row()) {
                        _static_row = std::move(mf);
                    } else {
                        if (mf->is_range_tombstone()) {
                            mf->as_range_tombstone().flip();
                        }
                        _mutation_fragments.emplace(std::move(*mf));
                    }
                    return stop_iteration::no;
                });
            }).then([&] {
                _source = { };
            });
        }
    public:
        explicit reversing_steamed_mutation(streamed_mutation sm)
            : streamed_mutation::impl(sm.schema(), sm.decorated_key(), sm.partition_tombstone())
            , _source(std::move(sm))
        { }

        virtual future<> fill_buffer() override {
            if (_source) {
                return consume_source().then([this] { return fill_buffer(); });
            }
            if (_static_row) {
                push_mutation_fragment(std::move(*_static_row));
                _static_row = { };
            }
            while (!is_end_of_stream() && !is_buffer_full()) {
                if (_mutation_fragments.empty()) {
                    _end_of_stream = true;
                } else {
                    push_mutation_fragment(std::move(_mutation_fragments.top()));
                    _mutation_fragments.pop();
                }
            }
            return make_ready_future<>();
        }
    };

    return make_streamed_mutation<reversing_steamed_mutation>(std::move(sm));
};

<|endoftext|>


<commit_before>/// \file util.cpp
/// Contains generic functions for managing processes and configuration.

#include "util.h"
#include <string.h>
#include <sys/types.h>
#include <signal.h>

#ifdef __FreeBSD__
#include <sys/wait.h>
#else
#include <wait.h>
#endif
#include <errno.h>
#include <iostream>
#include <sys/types.h>
#include <pwd.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>

std::map<pid_t, std::string> Util::Procs::plist;
bool Util::Procs::handler_set = false;

/// Sets the current process' running user
void Util::setUser(std::string username){
  if (username != "root"){
    struct passwd * user_info = getpwnam(username.c_str());
    if (!user_info){
      #if DEBUG >= 1
      fprintf(stderr, "Error: could not setuid %s: could not get PID\n", username.c_str());
      #endif
      return;
    }else{
      if (setuid(user_info->pw_uid) != 0){
        #if DEBUG >= 1
        fprintf(stderr, "Error: could not setuid %s: not allowed\n", username.c_str());
        #endif
      }else{
        #if DEBUG >= 3
        fprintf(stderr, "Changed user to %s\n", username.c_str());
        #endif
      }
    }
  }
}

/// Used internally to capture child signals and update plist.
void Util::Procs::childsig_handler(int signum){
  if (signum != SIGCHLD){return;}
  pid_t ret = wait(0);
  #if DEBUG >= 1
  std::string pname = plist[ret];
  #endif
  plist.erase(ret);
  #if DEBUG >= 1
  if (isActive(pname)){
    std::cerr << "Process " << pname << " half-terminated." << std::endl;
    Stop(pname);
  }else{
    std::cerr << "Process " << pname << " fully terminated." << std::endl;
  }
  #endif
}

/// Attempts to run the command cmd.
/// Replaces the current process - use after forking first!
/// This function will never return - it will either run the given
/// command or kill itself with return code 42.
void Util::Procs::runCmd(std::string & cmd){
  //split cmd into arguments
  //supports a maximum of 20 arguments
  char * tmp = (char*)cmd.c_str();
  char * tmp2 = 0;
  char * args[21];
  int i = 0;
  tmp2 = strtok(tmp, " ");
  args[0] = tmp2;
  while (tmp2 != 0 && (i < 20)){
    tmp2 = strtok(0, " ");
    ++i;
    args[i] = tmp2;
  }
  if (i == 20){args[20] = 0;}
  //execute the command
  execvp(args[0], args);
  #if DEBUG >= 1
  std::cerr << "Error running \"" << cmd << "\": " << strerror(errno) << std::endl;
  #endif
  _exit(42);
}

/// Starts a new process if the name is not already active.
/// \return 0 if process was not started, process PID otherwise.
/// \arg name Name for this process - only used internally.
/// \arg cmd Commandline for this process.
pid_t Util::Procs::Start(std::string name, std::string cmd){
  if (isActive(name)){return getPid(name);}
  if (!handler_set){
    struct sigaction new_action;
    new_action.sa_handler = Util::Procs::childsig_handler;
    sigemptyset(&new_action.sa_mask);
    new_action.sa_flags = 0;
    sigaction(SIGCHLD, &new_action, NULL);
    handler_set = true;
  }
  pid_t ret = fork();
  if (ret == 0){
    runCmd(cmd);
  }else{
    if (ret > 0){
      #if DEBUG >= 1
      std::cerr << "Process " << name << " started, PID " << ret << ": " << cmd << std::endl;
      #endif
      plist.insert(std::pair<pid_t, std::string>(ret, name));
    }else{
      #if DEBUG >= 1
      std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
      #endif
      return 0;
    }
  }
  return ret;
}

/// Starts two piped processes if the name is not already active.
/// \return 0 if process was not started, main (receiving) process PID otherwise.
/// \arg name Name for this process - only used internally.
/// \arg cmd Commandline for sub (sending) process.
/// \arg cmd2 Commandline for main (receiving) process.
pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
  if (isActive(name)){return getPid(name);}
  if (!handler_set){
    struct sigaction new_action;
    new_action.sa_handler = Util::Procs::childsig_handler;
    sigemptyset(&new_action.sa_mask);
    new_action.sa_flags = 0;
    sigaction(SIGCHLD, &new_action, NULL);
    handler_set = true;
  }
  int pfildes[2];
  if (pipe(pfildes) == -1){
    #if DEBUG >= 1
    std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl;
    #endif
    return 0;
  }

  pid_t ret = fork();
  if (ret == 0){
    close(pfildes[0]);
    dup2(pfildes[1],1);
    close(pfildes[1]);
    runCmd(cmd);
  }else{
    if (ret > 0){
      plist.insert(std::pair<pid_t, std::string>(ret, name));
    }else{
      #if DEBUG >= 1
      std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
      #endif
      close(pfildes[1]);
      close(pfildes[0]);
      return 0;
    }
  }

  pid_t ret2 = fork();
  if (ret2 == 0){
    close(pfildes[1]);
    dup2(pfildes[0],0);
    close(pfildes[0]);
    runCmd(cmd2);
  }else{
    if (ret2 > 0){
      #if DEBUG >= 1
        std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << "): " << cmd << " | " << cmd2 << std::endl;
      #endif
      plist.insert(std::pair<pid_t, std::string>(ret2, name));
    }else{
      #if DEBUG >= 1
      std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
      #endif
      Stop(name);
      close(pfildes[1]);
      close(pfildes[0]);
      return 0;
    }
  }
  close(pfildes[1]);
  close(pfildes[0]);
  return ret;
}

/// Stops the named process, if running.
/// \arg name (Internal) name of process to stop
void Util::Procs::Stop(std::string name){
  int max = 5;
  while (isActive(name)){
    Stop(getPid(name));
    max--;
    if (max <= 0){return;}
  }
}

/// Stops the process with this pid, if running.
/// \arg name The PID of the process to stop.
void Util::Procs::Stop(pid_t name){
  if (isActive(name)){
    kill(name, SIGTERM);
  }
}

/// (Attempts to) stop all running child processes.
void Util::Procs::StopAll(){
  std::map<pid_t, std::string>::iterator it;
  for (it = plist.begin(); it != plist.end(); it++){
    Stop((*it).first);
  }
}

/// Returns the number of active child processes.
int Util::Procs::Count(){
   return plist.size();
}

/// Returns true if a process by this name is currently active.
bool Util::Procs::isActive(std::string name){
  std::map<pid_t, std::string>::iterator it;
  for (it = plist.begin(); it != plist.end(); it++){
    if ((*it).second == name){return true;}
  }
  return false;
}

/// Returns true if a process with this PID is currently active.
bool Util::Procs::isActive(pid_t name){
  return (plist.count(name) == 1);
}

/// Gets PID for this named process, if active.
/// \return NULL if not active, process PID otherwise.
pid_t Util::Procs::getPid(std::string name){
  std::map<pid_t, std::string>::iterator it;
  for (it = plist.begin(); it != plist.end(); it++){
    if ((*it).second == name){return (*it).first;}
  }
  return 0;
}

/// Gets name for this process PID, if active.
/// \return Empty string if not active, name otherwise.
std::string Util::Procs::getName(pid_t name){
  if (plist.count(name) == 1){
    return plist[name];
  }
  return "";
}

/// Creates a new configuration manager.
Util::Config::Config(){
  listen_port = 4242;
  daemon_mode = true;
  interface = "0.0.0.0";
  configfile = "/etc/ddvtech.conf";
  username = "root";
  ignore_daemon = false;
  ignore_interface = false;
  ignore_port = false;
  ignore_user = false;
}

/// Parses commandline arguments.
/// Calls exit if an unknown option is encountered, printing a help message.
/// confsection must be either already set or never be set at all when this function is called.
/// In other words: do not change confsection after calling this function.
void Util::Config::parseArgs(int argc, char ** argv){
  int opt = 0;
  static const char *optString = "ndvp:i:u:c:h?";
  static const struct option longOpts[] = {
    {"help",0,0,'h'},
    {"port",1,0,'p'},
    {"interface",1,0,'i'},
    {"username",1,0,'u'},
    {"no-daemon",0,0,'n'},
    {"daemon",0,0,'d'},
    {"configfile",1,0,'c'},
    {"version",0,0,'v'}
  };
  while ((opt = getopt_long(argc, argv, optString, longOpts, 0)) != -1){
    switch (opt){
      case 'p': listen_port = atoi(optarg); ignore_port = true; break;
      case 'i': interface = optarg; ignore_interface = true; break;
      case 'n': daemon_mode = false; ignore_daemon = true; break;
      case 'd': daemon_mode = true; ignore_daemon = true; break;
      case 'c': configfile = optarg; break;
      case 'u': username = optarg; ignore_user = true; break;
      case 'v':
        printf("%s\n", TOSTRING(VERSION));
        exit(1);
        break;
      case 'h':
      case '?':
        std::string doingdaemon = "true";
        if (!daemon_mode){doingdaemon = "false";}
        if (confsection == ""){
          printf("Options: -h[elp], -?, -v[ersion], -n[odaemon], -d[aemon], -p[ort] VAL, -i[nterface] VAL, -u[sername] VAL\n");
          printf("Defaults:\n  interface: %s\n  port: %i\n  daemon mode: %s\n  username: %s\n", interface.c_str(), listen_port, doingdaemon.c_str(), username.c_str());
        }else{
          printf("Options: -h[elp], -?, -v[ersion], -n[odaemon], -d[aemon], -p[ort] VAL, -i[nterface] VAL, -c[onfigfile] VAL, -u[sername] VAL\n");
          printf("Defaults:\n  interface: %s\n  port: %i\n  daemon mode: %s\n  configfile: %s\n  username: %s\n", interface.c_str(), listen_port, doingdaemon.c_str(), configfile.c_str(), username.c_str());
          printf("Username root means no change to UID, no matter what the UID is.\n");
          printf("If the configfile exists, it is always loaded first. Commandline settings then overwrite the config file.\n");
          printf("\nThis process takes it directives from the %s section of the configfile.\n", confsection.c_str());
        }
        printf("This is %s version %s\n", argv[0], TOSTRING(VERSION));
        exit(1);
        break;
    }
  }//commandline options parser
}

/// Parses the configuration file at configfile, if it exists.
/// Assumes confsection is set.
void Util::Config::parseFile(){
  std::ifstream conf(configfile.c_str(), std::ifstream::in);
  std::string tmpstr;
  bool acc_comm = false;
  size_t foundeq;
  if (conf.fail()){
    #if DEBUG >= 3
    fprintf(stderr, "Configuration file %s not found - using build-in defaults...\n", configfile.c_str());
    #endif
  }else{
    while (conf.good()){
      getline(conf, tmpstr);
      if (tmpstr[0] == '['){//new section? check if we care.
        if (tmpstr == confsection){acc_comm = true;}else{acc_comm = false;}
      }else{
        if (!acc_comm){break;}//skip all lines in this section if we do not care about it
        foundeq = tmpstr.find('=');
        if (foundeq != std::string::npos){
          if ((tmpstr.substr(0, foundeq) == "port") && !ignore_port){listen_port = atoi(tmpstr.substr(foundeq+1).c_str());}
          if ((tmpstr.substr(0, foundeq) == "interface") && !ignore_interface){interface = tmpstr.substr(foundeq+1);}
          if ((tmpstr.substr(0, foundeq) == "username") && !ignore_user){username = tmpstr.substr(foundeq+1);}
          if ((tmpstr.substr(0, foundeq) == "daemon") && !ignore_daemon){daemon_mode = true;}
          if ((tmpstr.substr(0, foundeq) == "nodaemon") && !ignore_daemon){daemon_mode = false;}
        }//found equals sign
      }//section contents
    }//configfile line loop
  }//configuration
}

/// Will turn the current process into a daemon.
/// Works by calling daemon(1,0):
/// Does not change directory to root.
/// Does redirect output to /dev/null
void Util::Daemonize(){
  #if DEBUG >= 3
  fprintf(stderr, "Going into background mode...\n");
  #endif
  daemon(1, 0);
}
<commit_msg>Added closing of file descriptors to piped process starter (gets rid of ffmpeg junk output), added some extra debugging output to DDV Controller.<commit_after>/// \file util.cpp
/// Contains generic functions for managing processes and configuration.

#include "util.h"
#include <string.h>
#include <sys/types.h>
#include <signal.h>

#ifdef __FreeBSD__
#include <sys/wait.h>
#else
#include <wait.h>
#endif
#include <errno.h>
#include <iostream>
#include <sys/types.h>
#include <fcntl.h>
#include <pwd.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>

std::map<pid_t, std::string> Util::Procs::plist;
bool Util::Procs::handler_set = false;

/// Sets the current process' running user
void Util::setUser(std::string username){
  if (username != "root"){
    struct passwd * user_info = getpwnam(username.c_str());
    if (!user_info){
      #if DEBUG >= 1
      fprintf(stderr, "Error: could not setuid %s: could not get PID\n", username.c_str());
      #endif
      return;
    }else{
      if (setuid(user_info->pw_uid) != 0){
        #if DEBUG >= 1
        fprintf(stderr, "Error: could not setuid %s: not allowed\n", username.c_str());
        #endif
      }else{
        #if DEBUG >= 3
        fprintf(stderr, "Changed user to %s\n", username.c_str());
        #endif
      }
    }
  }
}

/// Used internally to capture child signals and update plist.
void Util::Procs::childsig_handler(int signum){
  if (signum != SIGCHLD){return;}
  pid_t ret = wait(0);
  #if DEBUG >= 1
  std::string pname = plist[ret];
  #endif
  plist.erase(ret);
  #if DEBUG >= 1
  if (isActive(pname)){
    std::cerr << "Process " << pname << " half-terminated." << std::endl;
    Stop(pname);
  }else{
    std::cerr << "Process " << pname << " fully terminated." << std::endl;
  }
  #endif
}

/// Attempts to run the command cmd.
/// Replaces the current process - use after forking first!
/// This function will never return - it will either run the given
/// command or kill itself with return code 42.
void Util::Procs::runCmd(std::string & cmd){
  //split cmd into arguments
  //supports a maximum of 20 arguments
  char * tmp = (char*)cmd.c_str();
  char * tmp2 = 0;
  char * args[21];
  int i = 0;
  tmp2 = strtok(tmp, " ");
  args[0] = tmp2;
  while (tmp2 != 0 && (i < 20)){
    tmp2 = strtok(0, " ");
    ++i;
    args[i] = tmp2;
  }
  if (i == 20){args[20] = 0;}
  //execute the command
  execvp(args[0], args);
  #if DEBUG >= 1
  std::cerr << "Error running \"" << cmd << "\": " << strerror(errno) << std::endl;
  #endif
  _exit(42);
}

/// Starts a new process if the name is not already active.
/// \return 0 if process was not started, process PID otherwise.
/// \arg name Name for this process - only used internally.
/// \arg cmd Commandline for this process.
pid_t Util::Procs::Start(std::string name, std::string cmd){
  if (isActive(name)){return getPid(name);}
  if (!handler_set){
    struct sigaction new_action;
    new_action.sa_handler = Util::Procs::childsig_handler;
    sigemptyset(&new_action.sa_mask);
    new_action.sa_flags = 0;
    sigaction(SIGCHLD, &new_action, NULL);
    handler_set = true;
  }
  pid_t ret = fork();
  if (ret == 0){
    runCmd(cmd);
  }else{
    if (ret > 0){
      #if DEBUG >= 1
      std::cerr << "Process " << name << " started, PID " << ret << ": " << cmd << std::endl;
      #endif
      plist.insert(std::pair<pid_t, std::string>(ret, name));
    }else{
      #if DEBUG >= 1
      std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
      #endif
      return 0;
    }
  }
  return ret;
}

/// Starts two piped processes if the name is not already active.
/// \return 0 if process was not started, main (receiving) process PID otherwise.
/// \arg name Name for this process - only used internally.
/// \arg cmd Commandline for sub (sending) process.
/// \arg cmd2 Commandline for main (receiving) process.
pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
  if (isActive(name)){return getPid(name);}
  if (!handler_set){
    struct sigaction new_action;
    new_action.sa_handler = Util::Procs::childsig_handler;
    sigemptyset(&new_action.sa_mask);
    new_action.sa_flags = 0;
    sigaction(SIGCHLD, &new_action, NULL);
    handler_set = true;
  }
  int pfildes[2];
  if (pipe(pfildes) == -1){
    #if DEBUG >= 1
    std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl;
    #endif
    return 0;
  }

  int devnull = open("/dev/null", O_RDWR);
  pid_t ret = fork();
  if (ret == 0){
    close(pfildes[0]);
    dup2(pfildes[1],STDOUT_FILENO);
    close(pfildes[1]);
    dup2(devnull, STDIN_FILENO);
    dup2(devnull, STDERR_FILENO);
    runCmd(cmd);
  }else{
    if (ret > 0){
      plist.insert(std::pair<pid_t, std::string>(ret, name));
    }else{
      #if DEBUG >= 1
      std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
      #endif
      close(pfildes[1]);
      close(pfildes[0]);
      return 0;
    }
  }

  pid_t ret2 = fork();
  if (ret2 == 0){
    close(pfildes[1]);
    dup2(pfildes[0],STDIN_FILENO);
    close(pfildes[0]);
    dup2(devnull, STDOUT_FILENO);
    dup2(devnull, STDERR_FILENO);
    runCmd(cmd2);
  }else{
    if (ret2 > 0){
      #if DEBUG >= 1
        std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << "): " << cmd << " | " << cmd2 << std::endl;
      #endif
      plist.insert(std::pair<pid_t, std::string>(ret2, name));
    }else{
      #if DEBUG >= 1
      std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
      #endif
      Stop(name);
      close(pfildes[1]);
      close(pfildes[0]);
      return 0;
    }
  }
  close(pfildes[1]);
  close(pfildes[0]);
  return ret;
}

/// Stops the named process, if running.
/// \arg name (Internal) name of process to stop
void Util::Procs::Stop(std::string name){
  int max = 5;
  while (isActive(name)){
    Stop(getPid(name));
    max--;
    if (max <= 0){return;}
  }
}

/// Stops the process with this pid, if running.
/// \arg name The PID of the process to stop.
void Util::Procs::Stop(pid_t name){
  if (isActive(name)){
    kill(name, SIGTERM);
  }
}

/// (Attempts to) stop all running child processes.
void Util::Procs::StopAll(){
  std::map<pid_t, std::string>::iterator it;
  for (it = plist.begin(); it != plist.end(); it++){
    Stop((*it).first);
  }
}

/// Returns the number of active child processes.
int Util::Procs::Count(){
   return plist.size();
}

/// Returns true if a process by this name is currently active.
bool Util::Procs::isActive(std::string name){
  std::map<pid_t, std::string>::iterator it;
  for (it = plist.begin(); it != plist.end(); it++){
    if ((*it).second == name){return true;}
  }
  return false;
}

/// Returns true if a process with this PID is currently active.
bool Util::Procs::isActive(pid_t name){
  return (plist.count(name) == 1);
}

/// Gets PID for this named process, if active.
/// \return NULL if not active, process PID otherwise.
pid_t Util::Procs::getPid(std::string name){
  std::map<pid_t, std::string>::iterator it;
  for (it = plist.begin(); it != plist.end(); it++){
    if ((*it).second == name){return (*it).first;}
  }
  return 0;
}

/// Gets name for this process PID, if active.
/// \return Empty string if not active, name otherwise.
std::string Util::Procs::getName(pid_t name){
  if (plist.count(name) == 1){
    return plist[name];
  }
  return "";
}

/// Creates a new configuration manager.
Util::Config::Config(){
  listen_port = 4242;
  daemon_mode = true;
  interface = "0.0.0.0";
  configfile = "/etc/ddvtech.conf";
  username = "root";
  ignore_daemon = false;
  ignore_interface = false;
  ignore_port = false;
  ignore_user = false;
}

/// Parses commandline arguments.
/// Calls exit if an unknown option is encountered, printing a help message.
/// confsection must be either already set or never be set at all when this function is called.
/// In other words: do not change confsection after calling this function.
void Util::Config::parseArgs(int argc, char ** argv){
  int opt = 0;
  static const char *optString = "ndvp:i:u:c:h?";
  static const struct option longOpts[] = {
    {"help",0,0,'h'},
    {"port",1,0,'p'},
    {"interface",1,0,'i'},
    {"username",1,0,'u'},
    {"no-daemon",0,0,'n'},
    {"daemon",0,0,'d'},
    {"configfile",1,0,'c'},
    {"version",0,0,'v'}
  };
  while ((opt = getopt_long(argc, argv, optString, longOpts, 0)) != -1){
    switch (opt){
      case 'p': listen_port = atoi(optarg); ignore_port = true; break;
      case 'i': interface = optarg; ignore_interface = true; break;
      case 'n': daemon_mode = false; ignore_daemon = true; break;
      case 'd': daemon_mode = true; ignore_daemon = true; break;
      case 'c': configfile = optarg; break;
      case 'u': username = optarg; ignore_user = true; break;
      case 'v':
        printf("%s\n", TOSTRING(VERSION));
        exit(1);
        break;
      case 'h':
      case '?':
        std::string doingdaemon = "true";
        if (!daemon_mode){doingdaemon = "false";}
        if (confsection == ""){
          printf("Options: -h[elp], -?, -v[ersion], -n[odaemon], -d[aemon], -p[ort] VAL, -i[nterface] VAL, -u[sername] VAL\n");
          printf("Defaults:\n  interface: %s\n  port: %i\n  daemon mode: %s\n  username: %s\n", interface.c_str(), listen_port, doingdaemon.c_str(), username.c_str());
        }else{
          printf("Options: -h[elp], -?, -v[ersion], -n[odaemon], -d[aemon], -p[ort] VAL, -i[nterface] VAL, -c[onfigfile] VAL, -u[sername] VAL\n");
          printf("Defaults:\n  interface: %s\n  port: %i\n  daemon mode: %s\n  configfile: %s\n  username: %s\n", interface.c_str(), listen_port, doingdaemon.c_str(), configfile.c_str(), username.c_str());
          printf("Username root means no change to UID, no matter what the UID is.\n");
          printf("If the configfile exists, it is always loaded first. Commandline settings then overwrite the config file.\n");
          printf("\nThis process takes it directives from the %s section of the configfile.\n", confsection.c_str());
        }
        printf("This is %s version %s\n", argv[0], TOSTRING(VERSION));
        exit(1);
        break;
    }
  }//commandline options parser
}

/// Parses the configuration file at configfile, if it exists.
/// Assumes confsection is set.
void Util::Config::parseFile(){
  std::ifstream conf(configfile.c_str(), std::ifstream::in);
  std::string tmpstr;
  bool acc_comm = false;
  size_t foundeq;
  if (conf.fail()){
    #if DEBUG >= 3
    fprintf(stderr, "Configuration file %s not found - using build-in defaults...\n", configfile.c_str());
    #endif
  }else{
    while (conf.good()){
      getline(conf, tmpstr);
      if (tmpstr[0] == '['){//new section? check if we care.
        if (tmpstr == confsection){acc_comm = true;}else{acc_comm = false;}
      }else{
        if (!acc_comm){break;}//skip all lines in this section if we do not care about it
        foundeq = tmpstr.find('=');
        if (foundeq != std::string::npos){
          if ((tmpstr.substr(0, foundeq) == "port") && !ignore_port){listen_port = atoi(tmpstr.substr(foundeq+1).c_str());}
          if ((tmpstr.substr(0, foundeq) == "interface") && !ignore_interface){interface = tmpstr.substr(foundeq+1);}
          if ((tmpstr.substr(0, foundeq) == "username") && !ignore_user){username = tmpstr.substr(foundeq+1);}
          if ((tmpstr.substr(0, foundeq) == "daemon") && !ignore_daemon){daemon_mode = true;}
          if ((tmpstr.substr(0, foundeq) == "nodaemon") && !ignore_daemon){daemon_mode = false;}
        }//found equals sign
      }//section contents
    }//configfile line loop
  }//configuration
}

/// Will turn the current process into a daemon.
/// Works by calling daemon(1,0):
/// Does not change directory to root.
/// Does redirect output to /dev/null
void Util::Daemonize(){
  #if DEBUG >= 3
  fprintf(stderr, "Going into background mode...\n");
  #endif
  daemon(1, 0);
}
<|endoftext|>


<commit_before>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2016                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#ifndef __LRU_CACHE__
#define __LRU_CACHE__

#include <ghoul/misc/assert.h>
//#include <modules/globebrowsing/datastructures/lrucache.h>

namespace openspace {

    template<typename KeyType, typename ValueType>
    LRUCache<KeyType, ValueType>::LRUCache(size_t size)
        : _cacheSize(size) { }

    template<typename KeyType, typename ValueType>
    LRUCache<KeyType, ValueType>::~LRUCache() {
        // Clean up list and map!
    }

    //////////////////////////////
    //		PUBLIC INTERFACE	//
    //////////////////////////////

    template<typename KeyType, typename ValueType>
    void LRUCache<KeyType, ValueType>::put(const KeyType& key, const ValueType& value)
    {
        auto it = _itemMap.find(key);
        if (it != _itemMap.end()) {
            _itemList.erase(it->second);
            _itemMap.erase(it);
        }
        _itemList.push_front(std::make_pair(key, value));
        _itemMap.insert(std::make_pair(key, _itemList.begin()));
        clean();
    }

    template<typename KeyType, typename ValueType>
    bool LRUCache<KeyType, ValueType>::exist(const KeyType& key) const
    {
        return _itemMap.count(key) > 0;
    }

    template<typename KeyType, typename ValueType>
    ValueType LRUCache<KeyType, ValueType>::get(const KeyType& key)
    {
        ghoul_assert(exist(key), "Key " << key << " must exist");
        auto it = _itemMap.find(key);
        // Move list iterator pointing to value
        _itemList.splice(_itemList.begin(), _itemList, it->second);
        return it->second->second;
    }

    template<typename KeyType, typename ValueType>
    size_t LRUCache<KeyType, ValueType>::size() const
    {
        return _itemMap.size();
    }

    //////////////////////////////
    //		PRIVATE HELPERS		//
    //////////////////////////////
    template<typename KeyType, typename ValueType>
    void LRUCache<KeyType, ValueType>::clean()
    {
        while (_itemMap.size() > _cacheSize) {
            auto last_it = _itemList.end(); last_it--;
            _itemMap.erase(last_it->first);
            _itemList.pop_back();
        }
    }

} // namespace openspace

#endif // !__LRU_CACHE__<commit_msg>Remove redundant safety check in LRU cache hashmap<commit_after>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2016                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#ifndef __LRU_CACHE__
#define __LRU_CACHE__

#include <ghoul/misc/assert.h>
//#include <modules/globebrowsing/datastructures/lrucache.h>

namespace openspace {

    template<typename KeyType, typename ValueType>
    LRUCache<KeyType, ValueType>::LRUCache(size_t size)
        : _cacheSize(size) { }

    template<typename KeyType, typename ValueType>
    LRUCache<KeyType, ValueType>::~LRUCache() {
        // Clean up list and map!
    }

    //////////////////////////////
    //		PUBLIC INTERFACE	//
    //////////////////////////////

    template<typename KeyType, typename ValueType>
    void LRUCache<KeyType, ValueType>::put(const KeyType& key, const ValueType& value)
    {
        auto it = _itemMap.find(key);
        if (it != _itemMap.end()) {
            _itemList.erase(it->second);
            _itemMap.erase(it);
        }
        _itemList.push_front(std::make_pair(key, value));
        _itemMap.insert(std::make_pair(key, _itemList.begin()));
        clean();
    }

    template<typename KeyType, typename ValueType>
    bool LRUCache<KeyType, ValueType>::exist(const KeyType& key) const
    {
        return _itemMap.count(key) > 0;
    }

    template<typename KeyType, typename ValueType>
    ValueType LRUCache<KeyType, ValueType>::get(const KeyType& key)
    {
        //ghoul_assert(exist(key), "Key " << key << " must exist");
        auto it = _itemMap.find(key);
        // Move list iterator pointing to value
        _itemList.splice(_itemList.begin(), _itemList, it->second);
        return it->second->second;
    }

    template<typename KeyType, typename ValueType>
    size_t LRUCache<KeyType, ValueType>::size() const
    {
        return _itemMap.size();
    }

    //////////////////////////////
    //		PRIVATE HELPERS		//
    //////////////////////////////
    template<typename KeyType, typename ValueType>
    void LRUCache<KeyType, ValueType>::clean()
    {
        while (_itemMap.size() > _cacheSize) {
            auto last_it = _itemList.end(); last_it--;
            _itemMap.erase(last_it->first);
            _itemList.pop_back();
        }
    }

} // namespace openspace

#endif // !__LRU_CACHE__<|endoftext|>


<commit_before>#include "SmoothCircleIC.h"

template<>
InputParameters validParams<SmoothCircleIC>()
{
  InputParameters params = validParams<InitialCondition>();
  params.addRequiredParam<Real>("x1", "The x coordinate of the circle center");
  params.addRequiredParam<Real>("y1", "The y coordinate of the circle center");
  params.addParam<Real>("z1", 0.0, "The z coordinate of the circle center");

  params.addRequiredParam<Real>("invalue", "The variable value inside the circle");
  params.addRequiredParam<Real>("outvalue", "The variable value outside the circle");
  params.addRequiredParam<Real>("radius", "The radius of a circle");
  params.addParam<Real>("int_width",0.0,"The interfacial width of the void surface.  Defaults to sharp interface");

  return params;
}

SmoothCircleIC::SmoothCircleIC(const std::string & name,
                               InputParameters parameters)
  :InitialCondition(name, parameters),
   _x1(parameters.get<Real>("x1")),
   _y1(parameters.get<Real>("y1")),
   _z1(parameters.get<Real>("z1")),
   _invalue(parameters.get<Real>("invalue")),
   _outvalue(parameters.get<Real>("outvalue")),
   _radius(parameters.get<Real>("radius")),
   _int_width(parameters.get<Real>("int_width")),
   _center(_x1,_y1,_z1)
{}

Real
SmoothCircleIC::value(const Point & p)
{
  Real value = 0.0;

  Real rad = 0.0;

  for(unsigned int i=0; i<LIBMESH_DIM; i++)
    rad += (p(i)-_center(i)) * (p(i)-_center(i));

  rad = sqrt(rad);

  if (rad <= _radius - _int_width/2.0)
    value = _invalue;
  else if (rad < _radius + _int_width/2.0)
  {
    Real int_pos = (rad - _radius + _int_width/2.0)/_int_width;
    value = _outvalue + (_invalue-_outvalue)*(1+cos(int_pos*3.14159))/2.0;
  }
  else
    value = _outvalue;

  return value;

}

RealGradient
SmoothCircleIC::gradient(const Point & p)
{
  Point pxminus = p, pxplus = p, pyminus = p, pyplus = p;
  pxminus(0) -= TOLERANCE;
  pyminus(1) -= TOLERANCE;
  pxplus(0)  += TOLERANCE;
  pyplus(1)  += TOLERANCE;
  Number uxminus = value(pxminus),
    uxplus  = value(pxplus),
    uyminus = value(pyminus),
    uyplus  = value(pyplus);
  return Gradient((uxplus-uxminus)/2./TOLERANCE,
                  (uyplus-uyminus)/2./TOLERANCE);
}

<commit_msg>added exact gradient to SmoothCircleIC<commit_after>#include "SmoothCircleIC.h"

template<>
InputParameters validParams<SmoothCircleIC>()
{
  InputParameters params = validParams<InitialCondition>();
  params.addRequiredParam<Real>("x1", "The x coordinate of the circle center");
  params.addRequiredParam<Real>("y1", "The y coordinate of the circle center");
  params.addParam<Real>("z1", 0.0, "The z coordinate of the circle center");

  params.addRequiredParam<Real>("invalue", "The variable value inside the circle");
  params.addRequiredParam<Real>("outvalue", "The variable value outside the circle");
  params.addRequiredParam<Real>("radius", "The radius of a circle");
  params.addParam<Real>("int_width",0.0,"The interfacial width of the void surface.  Defaults to sharp interface");

  return params;
}

SmoothCircleIC::SmoothCircleIC(const std::string & name,
                               InputParameters parameters)
  :InitialCondition(name, parameters),
   _x1(parameters.get<Real>("x1")),
   _y1(parameters.get<Real>("y1")),
   _z1(parameters.get<Real>("z1")),
   _invalue(parameters.get<Real>("invalue")),
   _outvalue(parameters.get<Real>("outvalue")),
   _radius(parameters.get<Real>("radius")),
   _int_width(parameters.get<Real>("int_width")),
   _center(_x1,_y1,_z1)
{}

Real
SmoothCircleIC::value(const Point & p)
{
  Real value = 0.0;

  Real rad = 0.0;

  for(unsigned int i=0; i<LIBMESH_DIM; i++)
    rad += (p(i)-_center(i)) * (p(i)-_center(i));

  rad = sqrt(rad);

  if (rad <= _radius - _int_width/2.0)
    value = _invalue;
  else if (rad < _radius + _int_width/2.0)
  {
    Real int_pos = (rad - _radius + _int_width/2.0)/_int_width;
    value = _outvalue + (_invalue-_outvalue)*(1+cos(int_pos*3.14159))/2.0;
  }
  else
    value = _outvalue;

  return value;

}

/*RealGradient
SmoothCircleIC::gradient(const Point & p)
{
  Point pxminus = p, pxplus = p, pyminus = p, pyplus = p;
  pxminus(0) -= TOLERANCE;
  pyminus(1) -= TOLERANCE;
  pxplus(0)  += TOLERANCE;
  pyplus(1)  += TOLERANCE;
  Number uxminus = value(pxminus),
    uxplus  = value(pxplus),
    uyminus = value(pyminus),
    uyplus  = value(pyplus);
  return Gradient((uxplus-uxminus)/2./TOLERANCE,
                  (uyplus-uyminus)/2./TOLERANCE);
                  }*/

RealGradient
SmoothCircleIC::gradient(const Point & p)
{
  Real DvalueDr = 0.0;

  Real rad = 0.0;

  for(unsigned int i=0; i<LIBMESH_DIM; i++)
    rad += (p(i)-_center(i)) * (p(i)-_center(i));

  rad = sqrt(rad);

  if (rad < _radius + _int_width/2.0 && rad > _radius - _int_width/2.0)
  {
    Real int_pos = (rad - _radius + _int_width/2.0)/_int_width;
    Real Dint_posDr = 1.0/_int_width;
    DvalueDr = Dint_posDr*(_invalue-_outvalue)*(-sin(int_pos*3.14159)*3.14159)/2.0;
  }

  if (rad != 0.0)
    return Gradient((p(0) - _center(0))*DvalueDr/rad,
                    (p(1) - _center(1))*DvalueDr/rad,
                    (p(2) - _center(2))*DvalueDr/rad);
  else
    return Gradient(0.0,0.0,0.0);

}

<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * 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.
 *****************************************************************************/

#include "modules/planning/common/decision_data.h"

namespace apollo {
namespace planning {

// this sanity check will move to the very beginning of planning
bool DecisionData::IsValidTrajectoryPoint(
  const common::TrajectoryPoint& point) {
  return !((!point.has_path_point()) || std::isnan(point.path_point().x()) ||
           std::isnan(point.path_point().y()) ||
           std::isnan(point.path_point().z()) ||
           std::isnan(point.path_point().kappa()) ||
           std::isnan(point.path_point().s()) ||
           std::isnan(point.path_point().dkappa()) ||
           std::isnan(point.path_point().ddkappa()) || std::isnan(point.v()) ||
           std::isnan(point.a()) || std::isnan(point.relative_time()));
}

bool DecisionData::IsValidTrajectory(
  const prediction::Trajectory& trajectory) {
  for (const auto& point : trajectory.trajectory_point()) {
    if (!IsValidTrajectoryPoint(point)) {
      AERROR << " TrajectoryPoint: " << trajectory.ShortDebugString()
             << " is NOT valid.";
      return false;
    }
  }
  return true;
}

DecisionData::DecisionData(
    const prediction::PredictionObstacles& prediction_obstacles,
    const ReferenceLine& reference_line)
    : reference_line_(reference_line) {
  for (const auto& prediction_obstacle :
       prediction_obstacles.prediction_obstacle()) {
    const std::string perception_id =
        std::to_string(prediction_obstacle.perception_obstacle().id());
    if (prediction_obstacle.trajectory().empty()) {
      obstacles_.emplace_back(new Obstacle(
          perception_id, prediction_obstacle.perception_obstacle()));
      continue;
    }
    int trajectory_index = 0;
    for (const auto& trajectory : prediction_obstacle.trajectory()) {
      if (!IsValidTrajectory(trajectory)) {
        AERROR << "obj:" << perception_id;
        continue;
      }
      const std::string obstacle_id =
          apollo::common::util::StrCat(perception_id, "_", trajectory_index);
      obstacles_.emplace_back(new Obstacle(
          obstacle_id, prediction_obstacle.perception_obstacle(), trajectory));
      ++trajectory_index;
    }
  }
}

PathObstacle* DecisionData::GetObstacleById(const std::string& id) {
  std::lock_guard<std::mutex> lock(mutex_);
  const auto it = obstacle_map_.find(id);
  if (it == obstacle_map_.end()) {
    return nullptr;
  }
  return it->second;
}

std::vector<PathObstacle*> DecisionData::GetObstacleByType(
    const VirtualObjectType& type) {
  std::vector<PathObstacle*> obstacles;
  std::lock_guard<std::mutex> lock(transaction_mutex_);

  std::vector<std::string> ids = GetObstacleIdByType(type);
  if (!ids.empty()) {
    return obstacles;
  }
  for (const std::string& id : ids) {
    obstacles.emplace_back();
    obstacles.back() = GetObstacleById(id);
    CHECK_NOTNULL(obstacles.back());
  }
  return obstacles;
}

std::vector<std::string> DecisionData::GetObstacleIdByType(
    const VirtualObjectType& type) {
  std::vector<std::string> ids;
  std::lock_guard<std::mutex> lock(mutex_);

  const auto it = virtual_obstacle_id_map_.find(type);
  if (it == virtual_obstacle_id_map_.end()) {
    return ids;
  }
  return it->second;
}

const std::vector<PathObstacle*>& DecisionData::GetStaticObstacle() const {
  return static_obstacle_;
}

const std::vector<PathObstacle*>& DecisionData::GetDynamicObstacle() const {
  return dynamic_obstacle_;
}

const std::vector<PathObstacle*>& DecisionData::GetVirtualObstacle() const {
  return virtual_obstacle_;
}

const std::vector<PathObstacle*>& DecisionData::GetPracticalObstacle() const {
  return practical_obstacle_;
}

const std::vector<PathObstacle*>& DecisionData::GetAllObstacle() const {
  return all_obstacle_;
}

bool DecisionData::CreateVirtualObstacle(const ReferencePoint& point,
                                         const VirtualObjectType& type,
                                         std::string* const id) {
  std::lock_guard<std::mutex> transaction_lock(transaction_mutex_);
  std::lock_guard<std::mutex> lock(mutex_);
  return false;
}
bool DecisionData::CreateVirtualObstacle(const double point_s,
                                         const VirtualObjectType& type,
                                         std::string* const id) {
  std::lock_guard<std::mutex> transaction_lock(transaction_mutex_);
  std::lock_guard<std::mutex> lock(mutex_);
  return false;
}

}  // namespace planning
}  // namespace apollo
<commit_msg>planning build path obstacle<commit_after>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * 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.
 *****************************************************************************/

#include "modules/planning/common/decision_data.h"

namespace apollo {
namespace planning {

// this sanity check will move to the very beginning of planning
bool DecisionData::IsValidTrajectoryPoint(
  const common::TrajectoryPoint& point) {
  return !((!point.has_path_point()) || std::isnan(point.path_point().x()) ||
           std::isnan(point.path_point().y()) ||
           std::isnan(point.path_point().z()) ||
           std::isnan(point.path_point().kappa()) ||
           std::isnan(point.path_point().s()) ||
           std::isnan(point.path_point().dkappa()) ||
           std::isnan(point.path_point().ddkappa()) || std::isnan(point.v()) ||
           std::isnan(point.a()) || std::isnan(point.relative_time()));
}

bool DecisionData::IsValidTrajectory(
  const prediction::Trajectory& trajectory) {
  for (const auto& point : trajectory.trajectory_point()) {
    if (!IsValidTrajectoryPoint(point)) {
      AERROR << " TrajectoryPoint: " << trajectory.ShortDebugString()
             << " is NOT valid.";
      return false;
    }
  }
  return true;
}

DecisionData::DecisionData(
    const prediction::PredictionObstacles& prediction_obstacles,
    const ReferenceLine& reference_line)
    : reference_line_(reference_line) {
  for (const auto& prediction_obstacle :
       prediction_obstacles.prediction_obstacle()) {
    const std::string perception_id =
        std::to_string(prediction_obstacle.perception_obstacle().id());
    if (prediction_obstacle.trajectory().empty()) {
      obstacles_.emplace_back(new Obstacle(
          perception_id, prediction_obstacle.perception_obstacle()));
      path_obstacles_.emplace_back(new PathObstacle(obstacles_.back().get()));
      all_obstacle_.emplace_back(path_obstacles_.back().get());
      practical_obstacle_.emplace_back(path_obstacles_.back().get());
      static_obstacle_.emplace_back(path_obstacles_.back().get());
      continue;
    }
    int trajectory_index = 0;
    for (const auto& trajectory : prediction_obstacle.trajectory()) {
      if (!IsValidTrajectory(trajectory)) {
        AERROR << "obj:" << perception_id;
        continue;
      }
      const std::string obstacle_id =
          apollo::common::util::StrCat(perception_id, "_", trajectory_index);
      obstacles_.emplace_back(new Obstacle(
          obstacle_id, prediction_obstacle.perception_obstacle(), trajectory));
      path_obstacles_.emplace_back(new PathObstacle(obstacles_.back().get()));
      all_obstacle_.emplace_back(path_obstacles_.back().get());
      practical_obstacle_.emplace_back(path_obstacles_.back().get());
      dynamic_obstacle_.emplace_back(path_obstacles_.back().get());
      ++trajectory_index;
    }
  }
}

PathObstacle* DecisionData::GetObstacleById(const std::string& id) {
  std::lock_guard<std::mutex> lock(mutex_);
  const auto it = obstacle_map_.find(id);
  if (it == obstacle_map_.end()) {
    return nullptr;
  }
  return it->second;
}

std::vector<PathObstacle*> DecisionData::GetObstacleByType(
    const VirtualObjectType& type) {
  std::vector<PathObstacle*> obstacles;
  std::lock_guard<std::mutex> lock(transaction_mutex_);

  std::vector<std::string> ids = GetObstacleIdByType(type);
  if (!ids.empty()) {
    return obstacles;
  }
  for (const std::string& id : ids) {
    obstacles.emplace_back();
    obstacles.back() = GetObstacleById(id);
    CHECK_NOTNULL(obstacles.back());
  }
  return obstacles;
}

std::vector<std::string> DecisionData::GetObstacleIdByType(
    const VirtualObjectType& type) {
  std::vector<std::string> ids;
  std::lock_guard<std::mutex> lock(mutex_);

  const auto it = virtual_obstacle_id_map_.find(type);
  if (it == virtual_obstacle_id_map_.end()) {
    return ids;
  }
  return it->second;
}

const std::vector<PathObstacle*>& DecisionData::GetStaticObstacle() const {
  return static_obstacle_;
}

const std::vector<PathObstacle*>& DecisionData::GetDynamicObstacle() const {
  return dynamic_obstacle_;
}

const std::vector<PathObstacle*>& DecisionData::GetVirtualObstacle() const {
  return virtual_obstacle_;
}

const std::vector<PathObstacle*>& DecisionData::GetPracticalObstacle() const {
  return practical_obstacle_;
}

const std::vector<PathObstacle*>& DecisionData::GetAllObstacle() const {
  return all_obstacle_;
}

bool DecisionData::CreateVirtualObstacle(const ReferencePoint& point,
                                         const VirtualObjectType& type,
                                         std::string* const id) {
  std::lock_guard<std::mutex> transaction_lock(transaction_mutex_);
  std::lock_guard<std::mutex> lock(mutex_);
  return false;
}
bool DecisionData::CreateVirtualObstacle(const double point_s,
                                         const VirtualObjectType& type,
                                         std::string* const id) {
  std::lock_guard<std::mutex> transaction_lock(transaction_mutex_);
  std::lock_guard<std::mutex> lock(mutex_);
  return false;
}

}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before>#include <Game/cServerAdapter.h>
#include <Network/cUDPServerManager.h>
#include <Network/cUDPManager.h>
#include <Network/cDeliverManager.h>
#include <Network/cEventManager.h>
#include <Network/cRequestManager.h>
#include <Network/cResponseManager.h>
namespace Game
{
cServerAdapter::cServerAdapter( )
{
	mQuarryId = 0;
	mPlayerFormats.insert( std::make_pair( 0, Network::Packet::PlayerFormat( 0, cinder::vec3( 30, 30, 20 ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 1, Network::Packet::PlayerFormat( 1, cinder::vec3( 32, 30, 20 ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 2, Network::Packet::PlayerFormat( 2, cinder::vec3( 34, 30, 20 ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 3, Network::Packet::PlayerFormat( 3, cinder::vec3( 36, 30, 20 ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 4, Network::Packet::PlayerFormat( 4, cinder::vec3( 30, 30, 30 ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 5, Network::Packet::PlayerFormat( 5, cinder::vec3( 30, 30, 32 ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 6, Network::Packet::PlayerFormat( 6, cinder::vec3( 30, 30, 34 ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 7, Network::Packet::PlayerFormat( 7, cinder::vec3( 30, 30, 36 ), cinder::quat( ) ) ) );
}
cServerAdapter::~cServerAdapter( )
{

}
void cServerAdapter::update( )
{
	sendPlayers( );
	sendSetQuarry( );
	sendGetGemPlayer( );
	sendGetGemQuarry( );
	sendBreakBlocks( );
}
void cServerAdapter::sendPlayers( )
{
	auto dli = Network::cDeliverManager::getInstance( );
	while ( auto packet = dli->getDliPlayer( ) )
	{
		try
		{
			auto id = packet->mFormat.playerId;
			mPlayerFormats[id].position = packet->mFormat.position;
			mPlayerFormats[id].rotation = packet->mFormat.rotation;
		}
		catch ( std::runtime_error e )
		{
			continue;
		}
	}
	auto eventPack = new Network::Packet::Event::cEvePlayers( );
	for ( auto& player : mPlayerFormats )
	{
		eventPack->mPlayerFormats.emplace_back( player.first, player.second.position, player.second.rotation );
	}
	Network::cUDPServerManager::getInstance( )->broadcast( eventPack );
}
void cServerAdapter::sendSetQuarry( )
{
	auto req = Network::cRequestManager::getInstance( );
	while ( auto packet = req->getReqCheckSetQuarry( ) )
	{
		mQuarryId += 1;
		mQuarrys.insert( mQuarryId );
		auto quarryPack = new Network::Packet::Response::cResCheckSetQuarry( );
		quarryPack->mDrillId = mQuarryId;
		quarryPack->mIsSucceeded = true;
		quarryPack->mPosition = packet->mPosition;
		quarryPack->mType = packet->mType;
		quarryPack->mTeamId = packet->mTeamId;

		if ( quarryPack->mIsSucceeded )
		{
			auto eventPack = new Network::Packet::Event::cEveSetQuarry( );
			eventPack->mDrillId = quarryPack->mDrillId;
			eventPack->mPosition = quarryPack->mPosition;
			eventPack->mType = quarryPack->mType;
			eventPack->mTeamId = quarryPack->mTeamId;
			Network::cUDPServerManager::getInstance( )->broadcastOthers( packet->mNetworkHandle, eventPack );
		}

		Network::cUDPServerManager::getInstance( )->send( packet->mNetworkHandle, quarryPack );
	}
}
void cServerAdapter::sendGetGemPlayer( )
{
	auto req = Network::cRequestManager::getInstance( );
	while ( auto packet = req->getReqCheckGetJemPlayer( ) )
	{
		try
		{
			auto resPack = new Network::Packet::Response::cResCheckGetJemPlayer( );
			auto isSuccess = mGems.insert( packet->mGemId ).second;

			resPack->mPlayerId = packet->mPlayerId;
			resPack->mGemId = packet->mGemId;
			resPack->mIsSuccessed = isSuccess;

			// Ȃ瑼̐lɉA΍̂As[܂B
			if ( isSuccess )
			{
				auto eventPack = new Network::Packet::Event::cEveGetJemPlayer( );
				eventPack->mPlayerId = packet->mPlayerId;
				eventPack->mGemId = packet->mGemId;
				Network::cUDPServerManager::getInstance( )->broadcastOthers( packet->mNetworkHandle, eventPack );
			}

			Network::cUDPServerManager::getInstance( )->send( packet->mNetworkHandle, resPack );
		}
		catch ( std::runtime_error e )
		{
			continue;
		}
	}
}
void cServerAdapter::sendGetGemQuarry( )
{
	auto req = Network::cRequestManager::getInstance( );
	while ( auto packet = req->getReqCheckGetJemQuarry( ) )
	{
		auto resPack = new Network::Packet::Response::cResCheckGetJemQuarry( );
		auto isSuccess = mGems.insert( packet->mGemId ).second;

		resPack->mDrillId = packet->mDrillId;
		resPack->mGemId = packet->mGemId;
		resPack->mIsSuccessed = isSuccess;

		// Ȃ瑼̐lɉ̌@@A΍̂As[܂B
		if ( isSuccess )
		{
			auto eventPack = new Network::Packet::Event::cEveGetJemQuarry( );
			eventPack->mDrillId = packet->mDrillId;
			eventPack->mGemId = packet->mGemId;
			Network::cUDPServerManager::getInstance( )->broadcastOthers( packet->mNetworkHandle, eventPack );
		}

		Network::cUDPServerManager::getInstance( )->send( packet->mNetworkHandle, resPack );
	}
}
void cServerAdapter::sendBreakBlocks( )
{
	auto dli = ::Network::cDeliverManager::getInstance( );
	auto breakBlocksPacket = new Network::Packet::Event::cEveBreakBlocks( );
	while ( auto packet = dli->getDliBreakBlocks( ) )
	{
		std::copy( packet->mBreakFormats.begin( ),
					  packet->mBreakFormats.end( ),
					  std::back_inserter( breakBlocksPacket->mBreakFormats ) );
	}
	if ( !breakBlocksPacket->mBreakFormats.empty( ) )
	{
		Network::cUDPServerManager::getInstance( )->broadcast( breakBlocksPacket );
	}
}
}
<commit_msg>適当にプレイヤーのリスポーン位置を設定しました。<commit_after>#include <Game/cServerAdapter.h>
#include <Network/cUDPServerManager.h>
#include <Network/cUDPManager.h>
#include <Network/cDeliverManager.h>
#include <Network/cEventManager.h>
#include <Network/cRequestManager.h>
#include <Network/cResponseManager.h>
#include <Game/Field/FieldData.h>
namespace Game
{
cServerAdapter::cServerAdapter( )
{
	ci::vec3 worldSize = ci::vec3( Game::Field::CHUNK_RANGE_X, Game::Field::CHUNK_RANGE_Y, Game::Field::CHUNK_RANGE_Z ) * Game::Field::BLOCK_SIZE * (float)Game::Field::CHUNK_SIZE;

	mQuarryId = 0;
	mPlayerFormats.insert( std::make_pair( 0, Network::Packet::PlayerFormat( 0, cinder::vec3( worldSize.x / 2 - 1.5F, worldSize.y + 1.0F, 7.0F ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 1, Network::Packet::PlayerFormat( 1, cinder::vec3( worldSize.x / 2 - 0.5F, worldSize.y + 1.0F, 7.0F ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 2, Network::Packet::PlayerFormat( 2, cinder::vec3( worldSize.x / 2 + 0.5F, worldSize.y + 1.0F, 7.0F ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 3, Network::Packet::PlayerFormat( 3, cinder::vec3( worldSize.x / 2 + 1.5F, worldSize.y + 1.0F, 7.0F ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 4, Network::Packet::PlayerFormat( 4, cinder::vec3( worldSize.x / 2 - 1.5F, worldSize.y + 1.0F, worldSize.z - 7.0F ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 5, Network::Packet::PlayerFormat( 5, cinder::vec3( worldSize.x / 2 - 0.5F, worldSize.y + 1.0F, worldSize.z - 7.0F ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 6, Network::Packet::PlayerFormat( 6, cinder::vec3( worldSize.x / 2 + 0.5F, worldSize.y + 1.0F, worldSize.z - 7.0F ), cinder::quat( ) ) ) );
	mPlayerFormats.insert( std::make_pair( 7, Network::Packet::PlayerFormat( 7, cinder::vec3( worldSize.x / 2 + 1.5F, worldSize.y + 1.0F, worldSize.z - 7.0F ), cinder::quat( ) ) ) );
}
cServerAdapter::~cServerAdapter( )
{

}
void cServerAdapter::update( )
{
	sendPlayers( );
	sendSetQuarry( );
	sendGetGemPlayer( );
	sendGetGemQuarry( );
	sendBreakBlocks( );
}
void cServerAdapter::sendPlayers( )
{
	auto dli = Network::cDeliverManager::getInstance( );
	while ( auto packet = dli->getDliPlayer( ) )
	{
		try
		{
			auto id = packet->mFormat.playerId;
			mPlayerFormats[id].position = packet->mFormat.position;
			mPlayerFormats[id].rotation = packet->mFormat.rotation;
		}
		catch ( std::runtime_error e )
		{
			continue;
		}
	}
	auto eventPack = new Network::Packet::Event::cEvePlayers( );
	for ( auto& player : mPlayerFormats )
	{
		eventPack->mPlayerFormats.emplace_back( player.first, player.second.position, player.second.rotation );
	}
	Network::cUDPServerManager::getInstance( )->broadcast( eventPack );
}
void cServerAdapter::sendSetQuarry( )
{
	auto req = Network::cRequestManager::getInstance( );
	while ( auto packet = req->getReqCheckSetQuarry( ) )
	{
		mQuarryId += 1;
		mQuarrys.insert( mQuarryId );
		auto quarryPack = new Network::Packet::Response::cResCheckSetQuarry( );
		quarryPack->mDrillId = mQuarryId;
		quarryPack->mIsSucceeded = true;
		quarryPack->mPosition = packet->mPosition;
		quarryPack->mType = packet->mType;
		quarryPack->mTeamId = packet->mTeamId;

		if ( quarryPack->mIsSucceeded )
		{
			auto eventPack = new Network::Packet::Event::cEveSetQuarry( );
			eventPack->mDrillId = quarryPack->mDrillId;
			eventPack->mPosition = quarryPack->mPosition;
			eventPack->mType = quarryPack->mType;
			eventPack->mTeamId = quarryPack->mTeamId;
			Network::cUDPServerManager::getInstance( )->broadcastOthers( packet->mNetworkHandle, eventPack );
		}

		Network::cUDPServerManager::getInstance( )->send( packet->mNetworkHandle, quarryPack );
	}
}
void cServerAdapter::sendGetGemPlayer( )
{
	auto req = Network::cRequestManager::getInstance( );
	while ( auto packet = req->getReqCheckGetJemPlayer( ) )
	{
		try
		{
			auto resPack = new Network::Packet::Response::cResCheckGetJemPlayer( );
			auto isSuccess = mGems.insert( packet->mGemId ).second;

			resPack->mPlayerId = packet->mPlayerId;
			resPack->mGemId = packet->mGemId;
			resPack->mIsSuccessed = isSuccess;

			// Ȃ瑼̐lɉA΍̂As[܂B
			if ( isSuccess )
			{
				auto eventPack = new Network::Packet::Event::cEveGetJemPlayer( );
				eventPack->mPlayerId = packet->mPlayerId;
				eventPack->mGemId = packet->mGemId;
				Network::cUDPServerManager::getInstance( )->broadcastOthers( packet->mNetworkHandle, eventPack );
			}

			Network::cUDPServerManager::getInstance( )->send( packet->mNetworkHandle, resPack );
		}
		catch ( std::runtime_error e )
		{
			continue;
		}
	}
}
void cServerAdapter::sendGetGemQuarry( )
{
	auto req = Network::cRequestManager::getInstance( );
	while ( auto packet = req->getReqCheckGetJemQuarry( ) )
	{
		auto resPack = new Network::Packet::Response::cResCheckGetJemQuarry( );
		auto isSuccess = mGems.insert( packet->mGemId ).second;

		resPack->mDrillId = packet->mDrillId;
		resPack->mGemId = packet->mGemId;
		resPack->mIsSuccessed = isSuccess;

		// Ȃ瑼̐lɉ̌@@A΍̂As[܂B
		if ( isSuccess )
		{
			auto eventPack = new Network::Packet::Event::cEveGetJemQuarry( );
			eventPack->mDrillId = packet->mDrillId;
			eventPack->mGemId = packet->mGemId;
			Network::cUDPServerManager::getInstance( )->broadcastOthers( packet->mNetworkHandle, eventPack );
		}

		Network::cUDPServerManager::getInstance( )->send( packet->mNetworkHandle, resPack );
	}
}
void cServerAdapter::sendBreakBlocks( )
{
	auto dli = ::Network::cDeliverManager::getInstance( );
	auto breakBlocksPacket = new Network::Packet::Event::cEveBreakBlocks( );
	while ( auto packet = dli->getDliBreakBlocks( ) )
	{
		std::copy( packet->mBreakFormats.begin( ),
					  packet->mBreakFormats.end( ),
					  std::back_inserter( breakBlocksPacket->mBreakFormats ) );
	}
	if ( !breakBlocksPacket->mBreakFormats.empty( ) )
	{
		Network::cUDPServerManager::getInstance( )->broadcast( breakBlocksPacket );
	}
}
}
<|endoftext|>