<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */
/*
 * Modified by ScyllaDB
 * Copyright (C) 2015 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 "cql3/cql_statement.hh"
#include "modification_statement.hh"
#include "raw/modification_statement.hh"
#include "raw/batch_statement.hh"
#include "service/storage_proxy.hh"
#include "transport/messages/result_message.hh"
#include "timestamp.hh"
#include "log.hh"
#include "to_string.hh"
#include <boost/algorithm/cxx11/any_of.hpp>
#include <boost/algorithm/cxx11/all_of.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/adaptor/uniqued.hpp>
#include <boost/iterator/counting_iterator.hpp>

#pragma once

namespace cql3 {

namespace statements {

/**
 * A BATCH statement parsed from a CQL query.
 *
 */
class batch_statement : public cql_statement_no_metadata {
    static logging::logger _logger;
public:
    using type = raw::batch_statement::type;
private:
    int _bound_terms;
public:
    type _type;
private:
    std::vector<shared_ptr<modification_statement>> _statements;
    std::unique_ptr<attributes> _attrs;
    bool _has_conditions;
    cql_stats& _stats;
public:
    /**
     * Creates a new BatchStatement from a list of statements and a
     * Thrift consistency level.
     *
     * @param type type of the batch
     * @param statements a list of UpdateStatements
     * @param attrs additional attributes for statement (CL, timestamp, timeToLive)
     */
    batch_statement(int bound_terms, type type_,
                    std::vector<shared_ptr<modification_statement>> statements,
                    std::unique_ptr<attributes> attrs,
                    cql_stats& stats);

    virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const override;

    virtual bool depends_on_keyspace(const sstring& ks_name) const override;

    virtual bool depends_on_column_family(const sstring& cf_name) const override;

    virtual uint32_t get_bound_terms() override;

    virtual future<> check_access(const service::client_state& state) override;

    // Validates a prepared batch statement without validating its nested statements.
    void validate();

    // The batch itself will be validated in either Parsed#prepare() - for regular CQL3 batches,
    //   or in QueryProcessor.processBatch() - for native protocol batches.
    virtual void validate(distributed<service::storage_proxy>& proxy, const service::client_state& state) override;

    const std::vector<shared_ptr<modification_statement>>& get_statements();
private:
    future<std::vector<mutation>> get_mutations(distributed<service::storage_proxy>& storage, const query_options& options, bool local, api::timestamp_type now, tracing::trace_state_ptr trace_state);

public:
    /**
     * Checks batch size to ensure threshold is met. If not, a warning is logged.
     * @param cfs ColumnFamilies that will store the batch's mutations.
     */
    static void verify_batch_size(const std::vector<mutation>& mutations);

    virtual future<shared_ptr<transport::messages::result_message>> execute(
            distributed<service::storage_proxy>& storage, service::query_state& state, const query_options& options) override;
private:
    future<shared_ptr<transport::messages::result_message>> execute(
            distributed<service::storage_proxy>& storage,
            service::query_state& query_state, const query_options& options,
            bool local, api::timestamp_type now);

    future<> execute_without_conditions(
            distributed<service::storage_proxy>& storage,
            std::vector<mutation> mutations,
            db::consistency_level cl,
            tracing::trace_state_ptr tr_state);

    future<shared_ptr<transport::messages::result_message>> execute_with_conditions(
            distributed<service::storage_proxy>& storage,
            const query_options& options,
            service::query_state& state);
public:
    virtual future<shared_ptr<transport::messages::result_message>> execute_internal(
            distributed<service::storage_proxy>& proxy,
            service::query_state& query_state, const query_options& options) override;

    // FIXME: no cql_statement::to_string() yet
#if 0
    sstring to_string() const {
        return sprint("BatchStatement(type=%s, statements=%s)", _type, join(", ", _statements));
    }
#endif
};

}
}
<commit_msg>cql3/statements: Make batch_statement::_type private<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */
/*
 * Modified by ScyllaDB
 * Copyright (C) 2015 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 "cql3/cql_statement.hh"
#include "modification_statement.hh"
#include "raw/modification_statement.hh"
#include "raw/batch_statement.hh"
#include "service/storage_proxy.hh"
#include "transport/messages/result_message.hh"
#include "timestamp.hh"
#include "log.hh"
#include "to_string.hh"
#include <boost/algorithm/cxx11/any_of.hpp>
#include <boost/algorithm/cxx11/all_of.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/adaptor/uniqued.hpp>
#include <boost/iterator/counting_iterator.hpp>

#pragma once

namespace cql3 {

namespace statements {

/**
 * A BATCH statement parsed from a CQL query.
 *
 */
class batch_statement : public cql_statement_no_metadata {
    static logging::logger _logger;
public:
    using type = raw::batch_statement::type;
private:
    int _bound_terms;
    type _type;
    std::vector<shared_ptr<modification_statement>> _statements;
    std::unique_ptr<attributes> _attrs;
    bool _has_conditions;
    cql_stats& _stats;
public:
    /**
     * Creates a new BatchStatement from a list of statements and a
     * Thrift consistency level.
     *
     * @param type type of the batch
     * @param statements a list of UpdateStatements
     * @param attrs additional attributes for statement (CL, timestamp, timeToLive)
     */
    batch_statement(int bound_terms, type type_,
                    std::vector<shared_ptr<modification_statement>> statements,
                    std::unique_ptr<attributes> attrs,
                    cql_stats& stats);

    virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const override;

    virtual bool depends_on_keyspace(const sstring& ks_name) const override;

    virtual bool depends_on_column_family(const sstring& cf_name) const override;

    virtual uint32_t get_bound_terms() override;

    virtual future<> check_access(const service::client_state& state) override;

    // Validates a prepared batch statement without validating its nested statements.
    void validate();

    // The batch itself will be validated in either Parsed#prepare() - for regular CQL3 batches,
    //   or in QueryProcessor.processBatch() - for native protocol batches.
    virtual void validate(distributed<service::storage_proxy>& proxy, const service::client_state& state) override;

    const std::vector<shared_ptr<modification_statement>>& get_statements();
private:
    future<std::vector<mutation>> get_mutations(distributed<service::storage_proxy>& storage, const query_options& options, bool local, api::timestamp_type now, tracing::trace_state_ptr trace_state);

public:
    /**
     * Checks batch size to ensure threshold is met. If not, a warning is logged.
     * @param cfs ColumnFamilies that will store the batch's mutations.
     */
    static void verify_batch_size(const std::vector<mutation>& mutations);

    virtual future<shared_ptr<transport::messages::result_message>> execute(
            distributed<service::storage_proxy>& storage, service::query_state& state, const query_options& options) override;
private:
    future<shared_ptr<transport::messages::result_message>> execute(
            distributed<service::storage_proxy>& storage,
            service::query_state& query_state, const query_options& options,
            bool local, api::timestamp_type now);

    future<> execute_without_conditions(
            distributed<service::storage_proxy>& storage,
            std::vector<mutation> mutations,
            db::consistency_level cl,
            tracing::trace_state_ptr tr_state);

    future<shared_ptr<transport::messages::result_message>> execute_with_conditions(
            distributed<service::storage_proxy>& storage,
            const query_options& options,
            service::query_state& state);
public:
    virtual future<shared_ptr<transport::messages::result_message>> execute_internal(
            distributed<service::storage_proxy>& proxy,
            service::query_state& query_state, const query_options& options) override;

    // FIXME: no cql_statement::to_string() yet
#if 0
    sstring to_string() const {
        return sprint("BatchStatement(type=%s, statements=%s)", _type, join(", ", _statements));
    }
#endif
};

}
}
<|endoftext|>


<commit_before>#include "taskbar.h"

using namespace Halley;

TaskBar::TaskBar(Resources& resources)
{
	{
		taskMaterial = std::make_shared<Material>(resources.get<MaterialDefinition>("distance_field_sprite.yaml"));
		auto& mat = *taskMaterial;
		mat["tex0"] = resources.get<Texture>("round_rect.png");
		mat["u_smoothness"] = 0.1f;
		mat["u_outline"] = 0.4f;

		taskSprite = Sprite()
			.setSize(Vector2f(64, 64))
			.setTexRect(Rect4f(0, 0, 1, 1));
	}

	{
		auto col = Colour4f(0.9882f, 0.15686f, 0.27843f, 1);
		halleyLogo = Sprite()
			.setImage(resources, "halley_logo_dist.png", "distance_field_sprite.yaml")
			.setPivot(Vector2f(0.5f, 0.5f))
			.setColour(col)
			.setScale(Vector2f(0.5f, 0.5f));
		auto& mat = halleyLogo.getMaterial();
		mat["u_smoothness"] = 0.4f;
		mat["u_outline"] = 0.0f;
		mat["u_outlineColour"] = col;
	}

	{
		Colour4f col(0.12f, 0.12f, 0.12f);
		barSolid = Sprite().setMaterial(resources, "solid_colour.yaml").setSize(Vector2f(1, 1)).setColour(col);
		barFade = Sprite().setImage(resources, "fade_right.png").setColour(col);
	}

	font = resources.get<Font>("ubuntub.yaml");
}

void TaskBar::update(const std::vector<EditorTaskAnchor>& taskData, Time time)
{
	// Flag them all as not running, so anything not found is accurately set as not running
	for (auto& t : tasks) {
		t.running = false;
		t.progress = 1;
		t.subLabel = "";
	}

	// Copy data
	for (auto& t : taskData) {
		if (t.isVisible() && t.getStatus() == EditorTaskStatus::Started) {
			auto& display = getDisplayForId(t.getId());
			display.label = t.getName();
			display.subLabel = t.getProgressLabel();
			display.progress = t.getProgress();
			display.running = true;
		}
	}

	// Update and decay
	for (size_t i = 0; i < tasks.size();) {
		auto& t = tasks[i];

		float targetDisplaySlot = float(i);
		if (t.displaySlot < 0) {
			t.displaySlot = targetDisplaySlot;
		} else {
			t.displaySlot = lerp(t.displaySlot, targetDisplaySlot, static_cast<float>(6 * time));
		}

		if (t.running) {
			t.progressDisplay = lerp(t.progressDisplay, t.progress, static_cast<float>(10 * time));
		} else {
			t.progressDisplay = 1;
			t.completeTime += static_cast<float>(time);
			if (t.completeTime >= 1.5f) {
				tasks.erase(tasks.begin() + i);
				continue;
			}
		}
		++i;
	}

	// Update bar size
	displaySize = lerp(displaySize, float(tasks.size()), 6 * time);
}

void TaskBar::draw(Painter& painter)
{
	// Setup for tasks
	auto view = painter.getViewPort();
	Vector2f anchor = Vector2f(view.getBottomLeft());
	Vector2f baseDrawPos = anchor + Vector2f(150, -72);
	Vector2f size = Vector2f(200, 40);
	float totalLen = baseDrawPos.x + (displaySize * size.x) + 10.0f;

	// Draw logo
	barSolid.setScale(Vector2f(totalLen, 32)).setPos(anchor + Vector2f(0, -56)).draw(painter);
	barFade.setPos(anchor + Vector2f(totalLen, -56)).draw(painter);
	halleyLogo.setPos(anchor + Vector2f(80, -41)).draw(painter);

	if (tasks.empty()) {
		// Nothing to do here!
		return;
	}

	// Setup text renderer
	TextRenderer text;
	text.setFont(font).setOffset(Vector2f(0, 0)).setColour(Colour(1, 1, 1)).setOutline(1.0f).setOutlineColour(Colour(0, 0, 0, 0.35f));

	// Draw tasks
	for (auto& t : tasks) {
		Vector2f drawPos = baseDrawPos + Vector2f((size.x + 20) * t.displaySlot, 0);

		//Colour col = t.progress > 0.9999f ? Colour(0.16f, 0.69f, 0.34f) : Colour(0.96f, 0.78f, 0.0f);
		Colour col = t.progress > 0.9999f ? Colour(0.16f, 0.69f, 0.34f) : Colour(0.18f, 0.53f, 0.87f);
		(*t.material)["u_outlineColour"] = col;

		// Background
		taskSprite.clone()
			.setMaterial(t.material)
			.setPos(drawPos)
			.setScale((size + Vector2f(24, 24)) / Vector2f(64, 64))
			.setColour(Colour4f(0.15f, 0.15f, 0.19f))
			.drawSliced(painter, Vector4f(0.45f, 0.45f, 0.45f, 0.45f));

		// Progress
		taskSprite.clone()
			.setMaterial(t.material)
			.setPos(drawPos)
			.setScale((size * Vector2f(t.progressDisplay, 1) + Vector2f(24, 24)) / Vector2f(64, 64))
			.setColour(col)
			.drawSliced(painter, Vector4f(0.45f, 0.45f, 0.45f, 0.45f));

		// Text
		text.setSize(14).setText(t.label).draw(painter, drawPos + Vector2f(24, 12));
		text.setSize(12).setText(t.subLabel).draw(painter, drawPos + Vector2f(24, 30));
	}
}

TaskBar::TaskDisplay& TaskBar::getDisplayForId(int id)
{
	for (auto& t : tasks) {
		if (t.id == id) {
			return t;
		}
	}

	tasks.push_back(TaskDisplay());
	TaskDisplay& display = tasks.back();

	display.material = std::make_shared<Material>(*taskMaterial);
	display.id = id;
	return display;
}
<commit_msg>Nicer usage of space on task bar.<commit_after>#include "taskbar.h"

using namespace Halley;

TaskBar::TaskBar(Resources& resources)
{
	{
		taskMaterial = std::make_shared<Material>(resources.get<MaterialDefinition>("distance_field_sprite.yaml"));
		auto& mat = *taskMaterial;
		mat["tex0"] = resources.get<Texture>("round_rect.png");
		mat["u_smoothness"] = 0.1f;
		mat["u_outline"] = 0.4f;

		taskSprite = Sprite()
			.setSize(Vector2f(64, 64))
			.setTexRect(Rect4f(0, 0, 1, 1));
	}

	{
		auto col = Colour4f(0.9882f, 0.15686f, 0.27843f, 1);
		halleyLogo = Sprite()
			.setImage(resources, "halley_logo_dist.png", "distance_field_sprite.yaml")
			.setPivot(Vector2f(0.5f, 0.5f))
			.setColour(col)
			.setScale(Vector2f(0.5f, 0.5f));
		auto& mat = halleyLogo.getMaterial();
		mat["u_smoothness"] = 0.4f;
		mat["u_outline"] = 0.0f;
		mat["u_outlineColour"] = col;
	}

	{
		Colour4f col(0.12f, 0.12f, 0.12f);
		barSolid = Sprite().setMaterial(resources, "solid_colour.yaml").setSize(Vector2f(1, 1)).setColour(col);
		barFade = Sprite().setImage(resources, "fade_right.png").setColour(col);
	}

	font = resources.get<Font>("ubuntub.yaml");
}

void TaskBar::update(const std::vector<EditorTaskAnchor>& taskData, Time time)
{
	// Flag them all as not running, so anything not found is accurately set as not running
	for (auto& t : tasks) {
		t.running = false;
		t.progress = 1;
		t.subLabel = "";
	}

	// Copy data
	for (auto& t : taskData) {
		if (t.isVisible() && t.getStatus() == EditorTaskStatus::Started) {
			auto& display = getDisplayForId(t.getId());
			display.label = t.getName();
			display.subLabel = t.getProgressLabel();
			display.progress = t.getProgress();
			display.running = true;
		}
	}

	// Update and decay
	for (size_t i = 0; i < tasks.size();) {
		auto& t = tasks[i];

		float targetDisplaySlot = float(i);
		if (t.displaySlot < 0) {
			t.displaySlot = targetDisplaySlot;
		} else {
			t.displaySlot = lerp(t.displaySlot, targetDisplaySlot, static_cast<float>(6 * time));
		}

		if (t.running) {
			t.progressDisplay = lerp(t.progressDisplay, t.progress, static_cast<float>(10 * time));
		} else {
			t.progressDisplay = 1;
			t.completeTime += static_cast<float>(time);
			if (t.completeTime >= 1.5f) {
				tasks.erase(tasks.begin() + i);
				continue;
			}
		}
		++i;
	}

	// Update bar size
	displaySize = lerp(displaySize, float(tasks.size()), static_cast<float>(6 * time));
}

void TaskBar::draw(Painter& painter)
{
	// Setup for tasks
	auto view = painter.getViewPort();
	Vector2f anchor = Vector2f(view.getBottomLeft());
	Vector2f baseDrawPos = anchor + Vector2f(150, -72);
	Vector2f size = Vector2f(std::min(400.0f, (view.getWidth() - baseDrawPos.x - 150) / std::max(1.0f, displaySize)), 40);
	float totalLen = baseDrawPos.x + (displaySize * size.x) + 10.0f;

	// Draw logo
	barSolid.setScale(Vector2f(totalLen, 32)).setPos(anchor + Vector2f(0, -56)).draw(painter);
	barFade.setPos(anchor + Vector2f(totalLen, -56)).draw(painter);
	halleyLogo.setPos(anchor + Vector2f(80, -41)).draw(painter);

	if (tasks.empty()) {
		// Nothing to do here!
		return;
	}

	// Setup text renderer
	TextRenderer text;
	text.setFont(font).setOffset(Vector2f(0, 0)).setColour(Colour(1, 1, 1)).setOutline(1.0f).setOutlineColour(Colour(0, 0, 0, 0.35f));

	// Draw tasks
	for (auto& t : tasks) {
		Vector2f drawPos = baseDrawPos + Vector2f((size.x + 20) * t.displaySlot, 0);

		//Colour col = t.progress > 0.9999f ? Colour(0.16f, 0.69f, 0.34f) : Colour(0.96f, 0.78f, 0.0f);
		Colour col = t.progress > 0.9999f ? Colour(0.16f, 0.69f, 0.34f) : Colour(0.18f, 0.53f, 0.87f);
		(*t.material)["u_outlineColour"] = col;

		// Background
		taskSprite.clone()
			.setMaterial(t.material)
			.setPos(drawPos)
			.setScale((size + Vector2f(24, 24)) / Vector2f(64, 64))
			.setColour(Colour4f(0.15f, 0.15f, 0.19f))
			.drawSliced(painter, Vector4f(0.45f, 0.45f, 0.45f, 0.45f));

		// Progress
		taskSprite.clone()
			.setMaterial(t.material)
			.setPos(drawPos)
			.setScale((size * Vector2f(t.progressDisplay, 1) + Vector2f(24, 24)) / Vector2f(64, 64))
			.setColour(col)
			.drawSliced(painter, Vector4f(0.45f, 0.45f, 0.45f, 0.45f));

		// Text
		text.setSize(14).setText(t.label).draw(painter, drawPos + Vector2f(24, 12));
		text.setSize(12).setText(t.subLabel).draw(painter, drawPos + Vector2f(24, 30));
	}
}

TaskBar::TaskDisplay& TaskBar::getDisplayForId(int id)
{
	for (auto& t : tasks) {
		if (t.id == id) {
			return t;
		}
	}

	tasks.push_back(TaskDisplay());
	TaskDisplay& display = tasks.back();

	display.material = std::make_shared<Material>(*taskMaterial);
	display.id = id;
	return display;
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */
/*
 * Modified by Cloudius Systems
 * Copyright 2015 Cloudius Systems
 */

/*
 * 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 "cql3/cql_statement.hh"
#include "modification_statement.hh"
#include "service/storage_proxy.hh"
#include "transport/messages/result_message.hh"
#include "timestamp.hh"
#include "log.hh"
#include "to_string.hh"
#include <boost/algorithm/cxx11/any_of.hpp>
#include <boost/algorithm/cxx11/all_of.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/adaptor/uniqued.hpp>
#include <boost/iterator/counting_iterator.hpp>

#pragma once

namespace cql3 {

namespace statements {

/**
 * A BATCH statement parsed from a CQL query.
 *
 */
class batch_statement : public cql_statement {
    static logging::logger _logger;
public:
    enum class type {
        LOGGED, UNLOGGED, COUNTER
    };
private:
    int _bound_terms;
public:
    type _type;
private:
    std::vector<shared_ptr<modification_statement>> _statements;
    std::unique_ptr<attributes> _attrs;
    bool _has_conditions;
public:
    /**
     * Creates a new BatchStatement from a list of statements and a
     * Thrift consistency level.
     *
     * @param type type of the batch
     * @param statements a list of UpdateStatements
     * @param attrs additional attributes for statement (CL, timestamp, timeToLive)
     */
    batch_statement(int bound_terms, type type_,
                    std::vector<shared_ptr<modification_statement>> statements,
                    std::unique_ptr<attributes> attrs)
            : _bound_terms(bound_terms), _type(type_), _statements(std::move(statements))
            , _attrs(std::move(attrs))
            , _has_conditions(boost::algorithm::any_of(_statements, std::mem_fn(&modification_statement::has_conditions))) {
    }

    virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const override {
        return _attrs->uses_function(ks_name, function_name)
                || boost::algorithm::any_of(_statements, [&] (auto&& s) { return s->uses_function(ks_name, function_name); });
    }

    virtual bool depends_on_keyspace(const sstring& ks_name) const override;

    virtual bool depends_on_column_family(const sstring& cf_name) const override;

    virtual uint32_t get_bound_terms() override {
        return _bound_terms;
    }

    virtual void check_access(const service::client_state& state) override {
        for (auto&& s : _statements) {
            s->check_access(state);
        }
    }

    // Validates a prepared batch statement without validating its nested statements.
    void validate() {
        if (_attrs->is_time_to_live_set()) {
            throw exceptions::invalid_request_exception("Global TTL on the BATCH statement is not supported.");
        }

        bool timestamp_set = _attrs->is_timestamp_set();
        if (timestamp_set) {
            if (_has_conditions) {
                throw exceptions::invalid_request_exception("Cannot provide custom timestamp for conditional BATCH");
            }
            if (_type == type::COUNTER) {
                throw exceptions::invalid_request_exception("Cannot provide custom timestamp for counter BATCH");
            }
        }

        bool has_counters = boost::algorithm::any_of(_statements, std::mem_fn(&modification_statement::is_counter));
        bool has_non_counters = !boost::algorithm::all_of(_statements, std::mem_fn(&modification_statement::is_counter));
        if (timestamp_set && has_counters) {
            throw exceptions::invalid_request_exception("Cannot provide custom timestamp for a BATCH containing counters");
        }
        if (timestamp_set && boost::algorithm::any_of(_statements, std::mem_fn(&modification_statement::is_timestamp_set))) {
            throw exceptions::invalid_request_exception("Timestamp must be set either on BATCH or individual statements");
        }
        if (_type == type::COUNTER && has_non_counters) {
            throw exceptions::invalid_request_exception("Cannot include non-counter statement in a counter batch");
        }
        if (_type == type::LOGGED && has_counters) {
            throw exceptions::invalid_request_exception("Cannot include a counter statement in a logged batch");
        }
        if (has_counters && has_non_counters) {
            throw exceptions::invalid_request_exception("Counter and non-counter mutations cannot exist in the same batch");
        }

        if (_has_conditions
                && !_statements.empty()
                && (boost::distance(_statements
                                | boost::adaptors::transformed(std::mem_fn(&modification_statement::keyspace))
                                | boost::adaptors::uniqued) != 1
                    || (boost::distance(_statements
                            | boost::adaptors::transformed(std::mem_fn(&modification_statement::column_family))
                            | boost::adaptors::uniqued) != 1))) {
            throw exceptions::invalid_request_exception("Batch with conditions cannot span multiple tables");
        }
    }

    // The batch itself will be validated in either Parsed#prepare() - for regular CQL3 batches,
    //   or in QueryProcessor.processBatch() - for native protocol batches.
    virtual void validate(distributed<service::storage_proxy>& proxy, const service::client_state& state) override {
        for (auto&& s : _statements) {
            s->validate(proxy, state);
        }
    }

    const std::vector<shared_ptr<modification_statement>>& get_statements() {
        return _statements;
    }
private:
    future<std::vector<mutation>> get_mutations(distributed<service::storage_proxy>& storage, const query_options& options, bool local, api::timestamp_type now) {
        struct collector {
            std::vector<mutation> _result;
            std::vector<mutation> get() && { return std::move(_result); }
            void operator()(std::vector<mutation> more) {
                std::move(more.begin(), more.end(), std::back_inserter(_result));
            }
        };
        auto get_mutations_for_statement = [this, &storage, &options, now, local] (size_t i) {
            auto&& statement = _statements[i];
            auto&& statement_options = options.for_statement(i);
            auto timestamp = _attrs->get_timestamp(now, statement_options);
            return statement->get_mutations(storage, statement_options, local, timestamp);
        };
        // FIXME: origin tries hard to merge mutations to same keyspace, for
        //        some reason.
        return map_reduce(
                boost::make_counting_iterator<size_t>(0),
                boost::make_counting_iterator<size_t>(_statements.size()),
                get_mutations_for_statement,
                collector());
    }

public:
    /**
     * Checks batch size to ensure threshold is met. If not, a warning is logged.
     * @param cfs ColumnFamilies that will store the batch's mutations.
     */
    static void verify_batch_size(const std::vector<mutation>& mutations);

    virtual future<shared_ptr<transport::messages::result_message>> execute(
            distributed<service::storage_proxy>& storage, service::query_state& state, const query_options& options) override {
        return execute(storage, state, options, false, options.get_timestamp(state));
    }
private:
    future<shared_ptr<transport::messages::result_message>> execute(
            distributed<service::storage_proxy>& storage,
            service::query_state& query_state, const query_options& options,
            bool local, api::timestamp_type now) {
        // FIXME: we don't support nulls here
#if 0
        if (options.get_consistency() == null)
            throw new InvalidRequestException("Invalid empty consistency level");
        if (options.getSerialConsistency() == null)
            throw new InvalidRequestException("Invalid empty serial consistency level");
#endif
        if (_has_conditions) {
            return execute_with_conditions(storage, options, query_state);
        }

        return get_mutations(storage, options, local, now).then([this, &storage, &options] (std::vector<mutation> ms) {
            return execute_without_conditions(storage, std::move(ms), options.get_consistency());
        }).then([] {
            return make_ready_future<shared_ptr<transport::messages::result_message>>(
                    make_shared<transport::messages::result_message::void_message>());
        });
    }

    future<> execute_without_conditions(
            distributed<service::storage_proxy>& storage,
            std::vector<mutation> mutations,
            db::consistency_level cl) {
        // FIXME: do we need to do this?
#if 0
        // Extract each collection of cfs from it's IMutation and then lazily concatenate all of them into a single Iterable.
        Iterable<ColumnFamily> cfs = Iterables.concat(Iterables.transform(mutations, new Function<IMutation, Collection<ColumnFamily>>()
        {
            public Collection<ColumnFamily> apply(IMutation im)
            {
                return im.getColumnFamilies();
            }
        }));
#endif
        verify_batch_size(mutations);

        bool mutate_atomic = _type == type::LOGGED && mutations.size() > 1;
        return storage.local().mutate_with_triggers(std::move(mutations), cl, mutate_atomic);
    }

    future<shared_ptr<transport::messages::result_message>> execute_with_conditions(
            distributed<service::storage_proxy>& storage,
            const query_options& options,
            service::query_state& state) {
        fail(unimplemented::cause::LWT);
#if 0
        auto now = state.get_timestamp();
        ByteBuffer key = null;
        String ksName = null;
        String cfName = null;
        CQL3CasRequest casRequest = null;
        Set<ColumnDefinition> columnsWithConditions = new LinkedHashSet<>();

        for (int i = 0; i < statements.size(); i++)
        {
            ModificationStatement statement = statements.get(i);
            QueryOptions statementOptions = options.forStatement(i);
            long timestamp = attrs.getTimestamp(now, statementOptions);
            List<ByteBuffer> pks = statement.buildPartitionKeyNames(statementOptions);
            if (pks.size() > 1)
                throw new IllegalArgumentException("Batch with conditions cannot span multiple partitions (you cannot use IN on the partition key)");
            if (key == null)
            {
                key = pks.get(0);
                ksName = statement.cfm.ksName;
                cfName = statement.cfm.cfName;
                casRequest = new CQL3CasRequest(statement.cfm, key, true);
            }
            else if (!key.equals(pks.get(0)))
            {
                throw new InvalidRequestException("Batch with conditions cannot span multiple partitions");
            }

            Composite clusteringPrefix = statement.createClusteringPrefix(statementOptions);
            if (statement.hasConditions())
            {
                statement.addConditions(clusteringPrefix, casRequest, statementOptions);
                // As soon as we have a ifNotExists, we set columnsWithConditions to null so that everything is in the resultSet
                if (statement.hasIfNotExistCondition() || statement.hasIfExistCondition())
                    columnsWithConditions = null;
                else if (columnsWithConditions != null)
                    Iterables.addAll(columnsWithConditions, statement.getColumnsWithConditions());
            }
            casRequest.addRowUpdate(clusteringPrefix, statement, statementOptions, timestamp);
        }

        ColumnFamily result = StorageProxy.cas(ksName, cfName, key, casRequest, options.getSerialConsistency(), options.getConsistency(), state.getClientState());

        return new ResultMessage.Rows(ModificationStatement.buildCasResultSet(ksName, key, cfName, result, columnsWithConditions, true, options.forStatement(0)));
#endif
    }

public:
    virtual future<shared_ptr<transport::messages::result_message>> execute_internal(
            distributed<service::storage_proxy>& proxy,
            service::query_state& query_state, const query_options& options) override {
        throw std::runtime_error(sprint("%s not implemented", __PRETTY_FUNCTION__));
#if 0
        assert !hasConditions;
        for (IMutation mutation : getMutations(BatchQueryOptions.withoutPerStatementVariables(options), true, queryState.getTimestamp()))
        {
            // We don't use counters internally.
            assert mutation instanceof Mutation;
            ((Mutation) mutation).apply();
        }
        return null;
#endif
    }

    // FIXME: no cql_statement::to_string() yet
#if 0
    sstring to_string() const {
        return sprint("BatchStatement(type=%s, statements=%s)", _type, join(", ", _statements));
    }
#endif

    class parsed : public cf_statement {
        type _type;
        shared_ptr<attributes::raw> _attrs;
        std::vector<shared_ptr<modification_statement::parsed>> _parsed_statements;
    public:
        parsed(
            type type_,
            shared_ptr<attributes::raw> attrs,
            std::vector<shared_ptr<modification_statement::parsed>> parsed_statements)
                : cf_statement(nullptr)
                , _type(type_)
                , _attrs(std::move(attrs))
                , _parsed_statements(std::move(parsed_statements)) {
        }

        virtual void prepare_keyspace(const service::client_state& state) override {
            for (auto&& s : _parsed_statements) {
                s->prepare_keyspace(state);
            }
        }

        virtual shared_ptr<parsed_statement::prepared> prepare(database& db) override {
            auto&& bound_names = get_bound_variables();

            std::vector<shared_ptr<modification_statement>> statements;
            for (auto&& parsed : _parsed_statements) {
                statements.push_back(parsed->prepare(db, bound_names));
            }

            auto&& prep_attrs = _attrs->prepare(db, "[batch]", "[batch]");
            prep_attrs->collect_marker_specification(bound_names);

            batch_statement batch_statement_(bound_names->size(), _type, std::move(statements), std::move(prep_attrs));
            batch_statement_.validate();

            return ::make_shared<parsed_statement::prepared>(make_shared(std::move(batch_statement_)),
                                                             bound_names->get_specifications());
        }
    };
};

}
}
<commit_msg>cql3: batch_statement: Execute statements sequentially<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */
/*
 * Modified by Cloudius Systems
 * Copyright 2015 Cloudius Systems
 */

/*
 * 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 "cql3/cql_statement.hh"
#include "modification_statement.hh"
#include "service/storage_proxy.hh"
#include "transport/messages/result_message.hh"
#include "timestamp.hh"
#include "log.hh"
#include "to_string.hh"
#include <boost/algorithm/cxx11/any_of.hpp>
#include <boost/algorithm/cxx11/all_of.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/adaptor/uniqued.hpp>
#include <boost/iterator/counting_iterator.hpp>

#pragma once

namespace cql3 {

namespace statements {

/**
 * A BATCH statement parsed from a CQL query.
 *
 */
class batch_statement : public cql_statement {
    static logging::logger _logger;
public:
    enum class type {
        LOGGED, UNLOGGED, COUNTER
    };
private:
    int _bound_terms;
public:
    type _type;
private:
    std::vector<shared_ptr<modification_statement>> _statements;
    std::unique_ptr<attributes> _attrs;
    bool _has_conditions;
public:
    /**
     * Creates a new BatchStatement from a list of statements and a
     * Thrift consistency level.
     *
     * @param type type of the batch
     * @param statements a list of UpdateStatements
     * @param attrs additional attributes for statement (CL, timestamp, timeToLive)
     */
    batch_statement(int bound_terms, type type_,
                    std::vector<shared_ptr<modification_statement>> statements,
                    std::unique_ptr<attributes> attrs)
            : _bound_terms(bound_terms), _type(type_), _statements(std::move(statements))
            , _attrs(std::move(attrs))
            , _has_conditions(boost::algorithm::any_of(_statements, std::mem_fn(&modification_statement::has_conditions))) {
    }

    virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const override {
        return _attrs->uses_function(ks_name, function_name)
                || boost::algorithm::any_of(_statements, [&] (auto&& s) { return s->uses_function(ks_name, function_name); });
    }

    virtual bool depends_on_keyspace(const sstring& ks_name) const override;

    virtual bool depends_on_column_family(const sstring& cf_name) const override;

    virtual uint32_t get_bound_terms() override {
        return _bound_terms;
    }

    virtual void check_access(const service::client_state& state) override {
        for (auto&& s : _statements) {
            s->check_access(state);
        }
    }

    // Validates a prepared batch statement without validating its nested statements.
    void validate() {
        if (_attrs->is_time_to_live_set()) {
            throw exceptions::invalid_request_exception("Global TTL on the BATCH statement is not supported.");
        }

        bool timestamp_set = _attrs->is_timestamp_set();
        if (timestamp_set) {
            if (_has_conditions) {
                throw exceptions::invalid_request_exception("Cannot provide custom timestamp for conditional BATCH");
            }
            if (_type == type::COUNTER) {
                throw exceptions::invalid_request_exception("Cannot provide custom timestamp for counter BATCH");
            }
        }

        bool has_counters = boost::algorithm::any_of(_statements, std::mem_fn(&modification_statement::is_counter));
        bool has_non_counters = !boost::algorithm::all_of(_statements, std::mem_fn(&modification_statement::is_counter));
        if (timestamp_set && has_counters) {
            throw exceptions::invalid_request_exception("Cannot provide custom timestamp for a BATCH containing counters");
        }
        if (timestamp_set && boost::algorithm::any_of(_statements, std::mem_fn(&modification_statement::is_timestamp_set))) {
            throw exceptions::invalid_request_exception("Timestamp must be set either on BATCH or individual statements");
        }
        if (_type == type::COUNTER && has_non_counters) {
            throw exceptions::invalid_request_exception("Cannot include non-counter statement in a counter batch");
        }
        if (_type == type::LOGGED && has_counters) {
            throw exceptions::invalid_request_exception("Cannot include a counter statement in a logged batch");
        }
        if (has_counters && has_non_counters) {
            throw exceptions::invalid_request_exception("Counter and non-counter mutations cannot exist in the same batch");
        }

        if (_has_conditions
                && !_statements.empty()
                && (boost::distance(_statements
                                | boost::adaptors::transformed(std::mem_fn(&modification_statement::keyspace))
                                | boost::adaptors::uniqued) != 1
                    || (boost::distance(_statements
                            | boost::adaptors::transformed(std::mem_fn(&modification_statement::column_family))
                            | boost::adaptors::uniqued) != 1))) {
            throw exceptions::invalid_request_exception("Batch with conditions cannot span multiple tables");
        }
    }

    // The batch itself will be validated in either Parsed#prepare() - for regular CQL3 batches,
    //   or in QueryProcessor.processBatch() - for native protocol batches.
    virtual void validate(distributed<service::storage_proxy>& proxy, const service::client_state& state) override {
        for (auto&& s : _statements) {
            s->validate(proxy, state);
        }
    }

    const std::vector<shared_ptr<modification_statement>>& get_statements() {
        return _statements;
    }
private:
    future<std::vector<mutation>> get_mutations(distributed<service::storage_proxy>& storage, const query_options& options, bool local, api::timestamp_type now) {
        // Do not process in parallel because operations like list append/prepend depend on execution order.
        return do_with(std::vector<mutation>(), [this, &storage, &options, now, local] (auto&& result) {
            return do_for_each(boost::make_counting_iterator<size_t>(0),
                               boost::make_counting_iterator<size_t>(_statements.size()),
                               [this, &storage, &options, now, local, &result] (size_t i) {
                auto&& statement = _statements[i];
                auto&& statement_options = options.for_statement(i);
                auto timestamp = _attrs->get_timestamp(now, statement_options);
                return statement->get_mutations(storage, statement_options, local, timestamp).then([&result] (auto&& more) {
                    std::move(more.begin(), more.end(), std::back_inserter(result));
                });
            }).then([&result] {
                return std::move(result);
            });
        });
    }

public:
    /**
     * Checks batch size to ensure threshold is met. If not, a warning is logged.
     * @param cfs ColumnFamilies that will store the batch's mutations.
     */
    static void verify_batch_size(const std::vector<mutation>& mutations);

    virtual future<shared_ptr<transport::messages::result_message>> execute(
            distributed<service::storage_proxy>& storage, service::query_state& state, const query_options& options) override {
        return execute(storage, state, options, false, options.get_timestamp(state));
    }
private:
    future<shared_ptr<transport::messages::result_message>> execute(
            distributed<service::storage_proxy>& storage,
            service::query_state& query_state, const query_options& options,
            bool local, api::timestamp_type now) {
        // FIXME: we don't support nulls here
#if 0
        if (options.get_consistency() == null)
            throw new InvalidRequestException("Invalid empty consistency level");
        if (options.getSerialConsistency() == null)
            throw new InvalidRequestException("Invalid empty serial consistency level");
#endif
        if (_has_conditions) {
            return execute_with_conditions(storage, options, query_state);
        }

        return get_mutations(storage, options, local, now).then([this, &storage, &options] (std::vector<mutation> ms) {
            return execute_without_conditions(storage, std::move(ms), options.get_consistency());
        }).then([] {
            return make_ready_future<shared_ptr<transport::messages::result_message>>(
                    make_shared<transport::messages::result_message::void_message>());
        });
    }

    future<> execute_without_conditions(
            distributed<service::storage_proxy>& storage,
            std::vector<mutation> mutations,
            db::consistency_level cl) {
        // FIXME: do we need to do this?
#if 0
        // Extract each collection of cfs from it's IMutation and then lazily concatenate all of them into a single Iterable.
        Iterable<ColumnFamily> cfs = Iterables.concat(Iterables.transform(mutations, new Function<IMutation, Collection<ColumnFamily>>()
        {
            public Collection<ColumnFamily> apply(IMutation im)
            {
                return im.getColumnFamilies();
            }
        }));
#endif
        verify_batch_size(mutations);

        bool mutate_atomic = _type == type::LOGGED && mutations.size() > 1;
        return storage.local().mutate_with_triggers(std::move(mutations), cl, mutate_atomic);
    }

    future<shared_ptr<transport::messages::result_message>> execute_with_conditions(
            distributed<service::storage_proxy>& storage,
            const query_options& options,
            service::query_state& state) {
        fail(unimplemented::cause::LWT);
#if 0
        auto now = state.get_timestamp();
        ByteBuffer key = null;
        String ksName = null;
        String cfName = null;
        CQL3CasRequest casRequest = null;
        Set<ColumnDefinition> columnsWithConditions = new LinkedHashSet<>();

        for (int i = 0; i < statements.size(); i++)
        {
            ModificationStatement statement = statements.get(i);
            QueryOptions statementOptions = options.forStatement(i);
            long timestamp = attrs.getTimestamp(now, statementOptions);
            List<ByteBuffer> pks = statement.buildPartitionKeyNames(statementOptions);
            if (pks.size() > 1)
                throw new IllegalArgumentException("Batch with conditions cannot span multiple partitions (you cannot use IN on the partition key)");
            if (key == null)
            {
                key = pks.get(0);
                ksName = statement.cfm.ksName;
                cfName = statement.cfm.cfName;
                casRequest = new CQL3CasRequest(statement.cfm, key, true);
            }
            else if (!key.equals(pks.get(0)))
            {
                throw new InvalidRequestException("Batch with conditions cannot span multiple partitions");
            }

            Composite clusteringPrefix = statement.createClusteringPrefix(statementOptions);
            if (statement.hasConditions())
            {
                statement.addConditions(clusteringPrefix, casRequest, statementOptions);
                // As soon as we have a ifNotExists, we set columnsWithConditions to null so that everything is in the resultSet
                if (statement.hasIfNotExistCondition() || statement.hasIfExistCondition())
                    columnsWithConditions = null;
                else if (columnsWithConditions != null)
                    Iterables.addAll(columnsWithConditions, statement.getColumnsWithConditions());
            }
            casRequest.addRowUpdate(clusteringPrefix, statement, statementOptions, timestamp);
        }

        ColumnFamily result = StorageProxy.cas(ksName, cfName, key, casRequest, options.getSerialConsistency(), options.getConsistency(), state.getClientState());

        return new ResultMessage.Rows(ModificationStatement.buildCasResultSet(ksName, key, cfName, result, columnsWithConditions, true, options.forStatement(0)));
#endif
    }

public:
    virtual future<shared_ptr<transport::messages::result_message>> execute_internal(
            distributed<service::storage_proxy>& proxy,
            service::query_state& query_state, const query_options& options) override {
        throw std::runtime_error(sprint("%s not implemented", __PRETTY_FUNCTION__));
#if 0
        assert !hasConditions;
        for (IMutation mutation : getMutations(BatchQueryOptions.withoutPerStatementVariables(options), true, queryState.getTimestamp()))
        {
            // We don't use counters internally.
            assert mutation instanceof Mutation;
            ((Mutation) mutation).apply();
        }
        return null;
#endif
    }

    // FIXME: no cql_statement::to_string() yet
#if 0
    sstring to_string() const {
        return sprint("BatchStatement(type=%s, statements=%s)", _type, join(", ", _statements));
    }
#endif

    class parsed : public cf_statement {
        type _type;
        shared_ptr<attributes::raw> _attrs;
        std::vector<shared_ptr<modification_statement::parsed>> _parsed_statements;
    public:
        parsed(
            type type_,
            shared_ptr<attributes::raw> attrs,
            std::vector<shared_ptr<modification_statement::parsed>> parsed_statements)
                : cf_statement(nullptr)
                , _type(type_)
                , _attrs(std::move(attrs))
                , _parsed_statements(std::move(parsed_statements)) {
        }

        virtual void prepare_keyspace(const service::client_state& state) override {
            for (auto&& s : _parsed_statements) {
                s->prepare_keyspace(state);
            }
        }

        virtual shared_ptr<parsed_statement::prepared> prepare(database& db) override {
            auto&& bound_names = get_bound_variables();

            std::vector<shared_ptr<modification_statement>> statements;
            for (auto&& parsed : _parsed_statements) {
                statements.push_back(parsed->prepare(db, bound_names));
            }

            auto&& prep_attrs = _attrs->prepare(db, "[batch]", "[batch]");
            prep_attrs->collect_marker_specification(bound_names);

            batch_statement batch_statement_(bound_names->size(), _type, std::move(statements), std::move(prep_attrs));
            batch_statement_.validate();

            return ::make_shared<parsed_statement::prepared>(make_shared(std::move(batch_statement_)),
                                                             bound_names->get_specifications());
        }
    };
};

}
}
<|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.

// https://github.com/pillarjs/path-to-regexp/blob/master/index.js

#include "path_to_regex.hpp"

namespace route {

const std::regex Path_to_regex::PATH_REGEXP =
  std::regex{"((\\\\.)|(([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))))"};

std::regex Path_to_regex::path_to_regex(const std::string& path, Keys& keys, const Options& options) {
  Tokens all_tokens = parse(path);
  tokens_to_keys(all_tokens, keys); // fill keys with relevant tokens
  return tokens_to_regex(all_tokens, options);
}

std::regex Path_to_regex::path_to_regex(const std::string& path,  const Options& options) {
  Tokens all_tokens = parse(path);
  return tokens_to_regex(all_tokens, options);
}

// Parse a string for the raw tokens
std::vector<Token> Path_to_regex::parse(const std::string& str) {
  if (str.empty())
    return {};

  Tokens tokens;
  int key = 0;
  int index = 0;
  std::string path = "";
  std::smatch res;

  for (std::sregex_iterator i = std::sregex_iterator{str.begin(), str.end(), PATH_REGEXP};
    i != std::sregex_iterator{}; ++i) {

    res = *i;

    std::string m = res[0];       // the parameter, f.ex. /:test
    std::string escaped = res[2];
    int offset = res.position();

    // JS: path += str.slice(index, offset); from and included index to and included offset-1
    path += str.substr(index, (offset - index));  // from index, number of chars: offset - index

    index = offset + m.size();

    if (not escaped.empty()) {
      path += escaped[1];   // if escaped == \a, escaped[1] == a (if str is "/\\a" f.ex.)
      continue;
    }

    std::string next = ((size_t) index < str.size()) ? std::string{str.at(index)} : "";

    std::string prefix = res[4];  // f.ex. /
    std::string name = res[5];    // f.ex. test
    std::string capture = res[6]; // f.ex. \d+
    std::string group = res[7];   // f.ex. (users|admins)
    std::string modifier = res[8];  // f.ex. ?
    std::string asterisk = res[9];  // * if path is /*

    // Push the current path onto the tokens
    if (not path.empty()) {
      Token stringToken;
      stringToken.set_string_token(path);
      tokens.push_back(stringToken);
      path = "";
    }

    bool partial = (not prefix.empty()) and (not next.empty()) and (next not_eq prefix);
    bool repeat = (modifier == "+") or (modifier == "*");
    bool optional = (modifier == "?") or (modifier == "*");
    std::string delimiter = (not prefix.empty()) ? prefix : "/";
    std::string pattern;

    if (not capture.empty())
      pattern = capture;
    else if (not group.empty())
      pattern = group;
    else
      pattern = (not asterisk.empty()) ? ".*" : ("[^" + delimiter + "]+?");

    Token t;
    t.name = (not name.empty()) ? name : std::to_string(key++);
    t.prefix = prefix;
    t.delimiter = delimiter;
    t.optional = optional;
    t.repeat = repeat;
    t.partial = partial;
    t.asterisk = (asterisk == "*");
    t.pattern = pattern;
    t.is_string = false;
    tokens.push_back(t);
  }

  // Match any characters still remaining
  if ((size_t) index < str.size())
    path += str.substr(index);

  // If the path exists, push it onto the end
  if (not path.empty()) {
    Token stringToken;
    stringToken.set_string_token(path);
    tokens.push_back(stringToken);
  }

  return tokens;
}

// Creates a regex based on the given tokens and options (optional)
std::regex Path_to_regex::tokens_to_regex(const Tokens& tokens, const Options& options) {
  if (tokens.empty())
    return std::regex{""};

  // Set default values for options:
  bool strict = false;
  bool sensitive = false;
  bool end = true;

  if (not options.empty()) {
    auto it = options.find("strict");
    strict = (it not_eq options.end()) ? options.find("strict")->second : false;

    it = options.find("sensitive");
    sensitive = (it not_eq options.end()) ? options.find("sensitive")->second : false;

    it = options.find("end");
    end = (it not_eq options.end()) ? options.find("end")->second : true;
  }

  std::string route = "";
  Token lastToken = tokens[tokens.size() - 1];
  std::regex re{"(.*\\/$)"};
  bool endsWithSlash = lastToken.is_string and std::regex_match(lastToken.name, re);
  // endsWithSlash if the last char in lastToken's name is a slash

  // Iterate over the tokens and create our regexp string
  for (size_t i = 0; i < tokens.size(); i++) {
    Token token = tokens[i];

    if (token.is_string) {
      route += token.name;
    } else {
      std::string prefix = token.prefix;
      std::string capture = "(?:" + token.pattern + ")";

      if (token.repeat)
        capture += "(?:" + prefix + capture + ")*";

      if (token.optional) {

        if (not token.partial)
          capture = "(?:" + prefix + "(" + capture + "))?";
        else
          capture = prefix + "(" + capture + ")?";

      } else {
        capture = prefix + "(" + capture + ")";
      }

      route += capture;
    }
  }

  // In non-strict mode we allow a slash at the end of match. If the path to
  // match already ends with a slash, we remove it for consistency. The slash
  // is valid at the end of a path match, not in the middle. This is important
  // in non-ending mode, where "/test/" shouldn't match "/test//route".

  if (not strict) {
    if (endsWithSlash)
      route = route.substr(0, (route.size() - 1));

    route += "(?:\\/(?=$))?";
  }

  if (end) {
    route += "$";
  } else {
    // In non-ending mode, we need the capturing groups to match as much as
    // possible by using a positive lookahead to the end or next path segment
    if (not (strict and endsWithSlash))
      route += "(?=\\/|$)";
  }

  if (sensitive)
    return std::regex{"^" + route};

  return std::regex{"^" + route, std::regex_constants::ECMAScript | std::regex_constants::icase};
}

void Path_to_regex::tokens_to_keys(const Tokens& tokens, Keys& keys) {
  for (size_t i = 0; i < tokens.size(); i++) {
    Token t = tokens[i];

    if (not t.is_string)
      keys.push_back(t);
  }
}

} //< namespace route
<commit_msg>Refactored Path_to_regex::tokens_to_keys<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.

// https://github.com/pillarjs/path-to-regexp/blob/master/index.js

#include "path_to_regex.hpp"

namespace route {

const std::regex Path_to_regex::PATH_REGEXP =
  std::regex{"((\\\\.)|(([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))))"};

std::regex Path_to_regex::path_to_regex(const std::string& path, Keys& keys, const Options& options) {
  Tokens all_tokens = parse(path);
  tokens_to_keys(all_tokens, keys); // fill keys with relevant tokens
  return tokens_to_regex(all_tokens, options);
}

std::regex Path_to_regex::path_to_regex(const std::string& path,  const Options& options) {
  Tokens all_tokens = parse(path);
  return tokens_to_regex(all_tokens, options);
}

// Parse a string for the raw tokens
std::vector<Token> Path_to_regex::parse(const std::string& str) {
  if (str.empty())
    return {};

  Tokens tokens;
  int key = 0;
  int index = 0;
  std::string path = "";
  std::smatch res;

  for (std::sregex_iterator i = std::sregex_iterator{str.begin(), str.end(), PATH_REGEXP};
    i != std::sregex_iterator{}; ++i) {

    res = *i;

    std::string m = res[0];       // the parameter, f.ex. /:test
    std::string escaped = res[2];
    int offset = res.position();

    // JS: path += str.slice(index, offset); from and included index to and included offset-1
    path += str.substr(index, (offset - index));  // from index, number of chars: offset - index

    index = offset + m.size();

    if (not escaped.empty()) {
      path += escaped[1];   // if escaped == \a, escaped[1] == a (if str is "/\\a" f.ex.)
      continue;
    }

    std::string next = ((size_t) index < str.size()) ? std::string{str.at(index)} : "";

    std::string prefix = res[4];  // f.ex. /
    std::string name = res[5];    // f.ex. test
    std::string capture = res[6]; // f.ex. \d+
    std::string group = res[7];   // f.ex. (users|admins)
    std::string modifier = res[8];  // f.ex. ?
    std::string asterisk = res[9];  // * if path is /*

    // Push the current path onto the tokens
    if (not path.empty()) {
      Token stringToken;
      stringToken.set_string_token(path);
      tokens.push_back(stringToken);
      path = "";
    }

    bool partial = (not prefix.empty()) and (not next.empty()) and (next not_eq prefix);
    bool repeat = (modifier == "+") or (modifier == "*");
    bool optional = (modifier == "?") or (modifier == "*");
    std::string delimiter = (not prefix.empty()) ? prefix : "/";
    std::string pattern;

    if (not capture.empty())
      pattern = capture;
    else if (not group.empty())
      pattern = group;
    else
      pattern = (not asterisk.empty()) ? ".*" : ("[^" + delimiter + "]+?");

    Token t;
    t.name = (not name.empty()) ? name : std::to_string(key++);
    t.prefix = prefix;
    t.delimiter = delimiter;
    t.optional = optional;
    t.repeat = repeat;
    t.partial = partial;
    t.asterisk = (asterisk == "*");
    t.pattern = pattern;
    t.is_string = false;
    tokens.push_back(t);
  }

  // Match any characters still remaining
  if ((size_t) index < str.size())
    path += str.substr(index);

  // If the path exists, push it onto the end
  if (not path.empty()) {
    Token stringToken;
    stringToken.set_string_token(path);
    tokens.push_back(stringToken);
  }

  return tokens;
}

// Creates a regex based on the given tokens and options (optional)
std::regex Path_to_regex::tokens_to_regex(const Tokens& tokens, const Options& options) {
  if (tokens.empty())
    return std::regex{""};

  // Set default values for options:
  bool strict = false;
  bool sensitive = false;
  bool end = true;

  if (not options.empty()) {
    auto it = options.find("strict");
    strict = (it not_eq options.end()) ? options.find("strict")->second : false;

    it = options.find("sensitive");
    sensitive = (it not_eq options.end()) ? options.find("sensitive")->second : false;

    it = options.find("end");
    end = (it not_eq options.end()) ? options.find("end")->second : true;
  }

  std::string route = "";
  Token lastToken = tokens[tokens.size() - 1];
  std::regex re{"(.*\\/$)"};
  bool endsWithSlash = lastToken.is_string and std::regex_match(lastToken.name, re);
  // endsWithSlash if the last char in lastToken's name is a slash

  // Iterate over the tokens and create our regexp string
  for (size_t i = 0; i < tokens.size(); i++) {
    Token token = tokens[i];

    if (token.is_string) {
      route += token.name;
    } else {
      std::string prefix = token.prefix;
      std::string capture = "(?:" + token.pattern + ")";

      if (token.repeat)
        capture += "(?:" + prefix + capture + ")*";

      if (token.optional) {

        if (not token.partial)
          capture = "(?:" + prefix + "(" + capture + "))?";
        else
          capture = prefix + "(" + capture + ")?";

      } else {
        capture = prefix + "(" + capture + ")";
      }

      route += capture;
    }
  }

  // In non-strict mode we allow a slash at the end of match. If the path to
  // match already ends with a slash, we remove it for consistency. The slash
  // is valid at the end of a path match, not in the middle. This is important
  // in non-ending mode, where "/test/" shouldn't match "/test//route".

  if (not strict) {
    if (endsWithSlash)
      route = route.substr(0, (route.size() - 1));

    route += "(?:\\/(?=$))?";
  }

  if (end) {
    route += "$";
  } else {
    // In non-ending mode, we need the capturing groups to match as much as
    // possible by using a positive lookahead to the end or next path segment
    if (not (strict and endsWithSlash))
      route += "(?=\\/|$)";
  }

  if (sensitive)
    return std::regex{"^" + route};

  return std::regex{"^" + route, std::regex_constants::ECMAScript | std::regex_constants::icase};
}

void Path_to_regex::tokens_to_keys(const Tokens& tokens, Keys& keys) {
  for (auto& token : tokens)
    if (not token.is_string)
      keys.push_back(t);
}

} //< namespace route
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * For use for simulation and test purposes only
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Marc Orr, Brad Beckmann
 */

#include <CL/cl.h>
#include <malloc.h>

#include <cstdio>
#include <cstring>
#include <fstream>
#include <string>

#define SUCCESS 0
#define FAILURE 1

// OpenCL datastructures
cl_context       context;
cl_device_id     *devices;
cl_command_queue commandQueue;
cl_program       program;
cl_kernel        readKernel;

// Application datastructures
const int CACHE_LINE_SIZE = 64;
size_t grid_size = 512;
size_t work_group_size = 256;

// arguments
const int code_size = 5;
const char *code = "hello";
int *keys;
char *msg;
int chars_decoded = 0;

/*
    Setup data structures for application/algorithm
*/
int
setupDataStructs()
{
    msg = (char *)memalign(CACHE_LINE_SIZE, (grid_size + 1) * sizeof(char));
    if (msg == NULL) {
        printf("%s:%d: error: %s\n", __FILE__, __LINE__,
               "could not allocate host buffers\n");
       exit(-1);
    }
    msg[grid_size] = '\0';

    keys = (int *)memalign(CACHE_LINE_SIZE, code_size * sizeof(int));
    keys[0] = 23;
    keys[1] = 0;
    keys[2] = 0;
    keys[3] = 0;
    keys[4] = 0;

    return SUCCESS;
}

/* Setup OpenCL data structures */
int
setupOpenCL()
{
    cl_int status = 0;
    size_t deviceListSize;

    // 1. Get platform
    cl_uint numPlatforms;
    cl_platform_id platform = NULL;
    status = clGetPlatformIDs(0, NULL, &numPlatforms);
    if (status != CL_SUCCESS) {
        printf("Error: Getting Platforms. (clGetPlatformsIDs)\n");
        return FAILURE;
    }

    if (numPlatforms > 0) {
        cl_platform_id *platforms = new cl_platform_id[numPlatforms];
        status = clGetPlatformIDs(numPlatforms, platforms, NULL);
        if (status != CL_SUCCESS) {
            printf("Error: Getting Platform Ids. (clGetPlatformsIDs)\n");
            return FAILURE;
        }
        for (int i = 0; i < numPlatforms; ++i) {
            char pbuff[100];
            status = clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR,
                                       sizeof(pbuff), pbuff, NULL);
            if (status != CL_SUCCESS) {
                printf("Error: Getting Platform Info.(clGetPlatformInfo)\n");
                return FAILURE;
            }
            platform = platforms[i];
            if (!strcmp(pbuff, "Advanced Micro Devices, Inc.")) {
                break;
            }
        }
        delete platforms;
    }

    if (NULL == platform) {
        printf("NULL platform found so Exiting Application.\n");
        return FAILURE;
    }

    // 2. create context from platform
    cl_context_properties cps[3] =
        {CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 0};
    context = clCreateContextFromType(cps, CL_DEVICE_TYPE_GPU, NULL, NULL,
                                      &status);
    if (status != CL_SUCCESS) {
        printf("Error: Creating Context. (clCreateContextFromType)\n");
        return FAILURE;
    }

    // 3. Get device info
    // 3a. Get # of devices
    status = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL,
                              &deviceListSize);
    if (status != CL_SUCCESS) {
        printf("Error: Getting Context Info (1st clGetContextInfo)\n");
        return FAILURE;
    }

    // 3b. Get the device list data
    devices = (cl_device_id *)malloc(deviceListSize);
    if (devices == 0) {
        printf("Error: No devices found.\n");
        return FAILURE;
    }
    status = clGetContextInfo(context, CL_CONTEXT_DEVICES, deviceListSize,
                              devices, NULL);
    if (status != CL_SUCCESS) {
        printf("Error: Getting Context Info (2nd clGetContextInfo)\n");
        return FAILURE;
    }

    // 4. Create command queue for device
    commandQueue = clCreateCommandQueue(context, devices[0], 0, &status);
    if (status != CL_SUCCESS) {
        printf("Creating Command Queue. (clCreateCommandQueue)\n");
        return FAILURE;
    }

    const char *source = "dummy text";

    size_t sourceSize[] = {strlen(source)};

    // 5b. Register the kernel with the runtime
    program = clCreateProgramWithSource(context, 1, &source, sourceSize,
                                        &status);
    if (status != CL_SUCCESS) {
      printf("Error: Loading kernel (clCreateProgramWithSource)\n");
      return FAILURE;
    }

    status = clBuildProgram(program, 1, devices, NULL, NULL, NULL);
    if (status != CL_SUCCESS) {
        printf("Error: Building kernel (clBuildProgram)\n");
        return FAILURE;
    }

    readKernel = clCreateKernel(program, "read_kernel", &status);
    if (status != CL_SUCCESS) {
        printf("Error: Creating readKernel from program. (clCreateKernel)\n");
        return FAILURE;
    }

    return SUCCESS;
}

/* Run kernels */
int
runCLKernel(cl_kernel kernel)
{
    cl_int   status;
    cl_event event;
    size_t globalThreads[1] = {grid_size};
    size_t localThreads[1] = {work_group_size};

    // 1. Set arguments
    // 1a. code size
    size_t code_size = strlen(code);
    status = clSetKernelArg(kernel, 0, sizeof(size_t), &code_size);
    if (status != CL_SUCCESS) {
        printf("Error: Setting kernel argument. (code_size)\n");
        return FAILURE;
    }

    // 1b. code
    status = clSetKernelArg(kernel, 1, sizeof(char *), (void *)&code);
    if (status != CL_SUCCESS) {
        printf("Error: Setting kernel argument. (code_in)\n");
        return FAILURE;
    }

    // 1c. keys
    printf("keys = %p, &keys = %p, keys[0] = %d\n", keys, &keys, keys[0]);
    status = clSetKernelArg(kernel, 2, sizeof(int *), (void *)&keys);
    if (status != CL_SUCCESS) {
        printf("Error: Setting kernel argument. (key_arr)\n");
        return FAILURE;
    }

    // 1d. msg
    status = clSetKernelArg(kernel, 3, sizeof(char *), (void *)&msg);
    if (status != CL_SUCCESS) {
        printf("Error: Setting kernel argument. (memOut)\n");
        return FAILURE;
    }

    // 1e. chars_decoded
    int *chars_decoded_ptr = &chars_decoded;
    status = clSetKernelArg(kernel, 4, sizeof(int *),
                            (void *)&chars_decoded_ptr);
    if (status != CL_SUCCESS) {
        printf("Error: Setting kernel argument. (memOut)\n");
        return FAILURE;
    }

    // 2. Launch kernel
    status = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL,
                                    globalThreads, localThreads, 0, NULL,
                                    &event);
    if (status != CL_SUCCESS) {
        printf("Error: Enqueue failed. (clEnqueueNDRangeKernel)\n");
        return FAILURE;
    }

    // 3. Wait for the kernel
    status = clWaitForEvents(1, &event);
    if (status != CL_SUCCESS) {
        printf("Error: Waiting for kernel run to finish. (clWaitForEvents)\n");
        return FAILURE;
    }

    // 4. Cleanup
    status = clReleaseEvent(event);
    if (status != CL_SUCCESS) {
        printf("Error: Release event object. (clReleaseEvent)\n");
        return FAILURE;
    }

    return SUCCESS;
}

/* Release OpenCL resources (Context, Memory etc.) */
int
cleanupCL()
{
    cl_int status;
    status = clReleaseKernel(readKernel);
    if (status != CL_SUCCESS) {
        printf("Error: In clReleaseKernel \n");
        return FAILURE;
    }
    status = clReleaseProgram(program);
    if (status != CL_SUCCESS) {
        printf("Error: In clReleaseProgram\n");
        return FAILURE;
    }
    status = clReleaseCommandQueue(commandQueue);
    if (status != CL_SUCCESS) {
        printf("Error: In clReleaseCommandQueue\n");
        return FAILURE;
    }
    status = clReleaseContext(context);
    if (status != CL_SUCCESS) {
        printf("Error: In clReleaseContext\n");
        return FAILURE;
    }

    return SUCCESS;
}

int
main(int argc, char * argv[])
{
    // Initialize Host application
    if (setupDataStructs() != SUCCESS) {
        return FAILURE;
    }

    // Initialize OpenCL resources
    if (setupOpenCL() != SUCCESS) {
        return FAILURE;
    }

    // Run the CL program
    if (runCLKernel(readKernel) != SUCCESS) {
        return FAILURE;
    }
    printf("the gpu says:\n");
    printf("%s\n", msg);

    // Releases OpenCL resources
    if (cleanupCL()!= SUCCESS) {
        return FAILURE;
    }

    return SUCCESS;
}
<commit_msg>tests: Add example of using KVM acceleration with an app<commit_after>/*
 * Copyright (c) 2015 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * For use for simulation and test purposes only
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Marc Orr, Brad Beckmann
 */

#include <CL/cl.h>
#include <malloc.h>

#include <cstdio>
#include <cstring>
#include <fstream>
#include <string>

#ifdef KVM_SWITCH
#include "m5op.h"

void *m5_mem = (void*)0xffffc90000000000;
#endif

#define SUCCESS 0
#define FAILURE 1

// OpenCL datastructures
cl_context       context;
cl_device_id     *devices;
cl_command_queue commandQueue;
cl_program       program;
cl_kernel        readKernel;

// Application datastructures
const int CACHE_LINE_SIZE = 64;
size_t grid_size = 512;
size_t work_group_size = 256;

// arguments
const int code_size = 5;
const char *code = "hello";
int *keys;
char *msg;
int chars_decoded = 0;

/*
    Setup data structures for application/algorithm
*/
int
setupDataStructs()
{
    msg = (char *)memalign(CACHE_LINE_SIZE, (grid_size + 1) * sizeof(char));
    if (msg == NULL) {
        printf("%s:%d: error: %s\n", __FILE__, __LINE__,
               "could not allocate host buffers\n");
       exit(-1);
    }
    msg[grid_size] = '\0';

    keys = (int *)memalign(CACHE_LINE_SIZE, code_size * sizeof(int));
    keys[0] = 23;
    keys[1] = 0;
    keys[2] = 0;
    keys[3] = 0;
    keys[4] = 0;

    return SUCCESS;
}

/* Setup OpenCL data structures */
int
setupOpenCL()
{
    cl_int status = 0;
    size_t deviceListSize;

    // 1. Get platform
    cl_uint numPlatforms;
    cl_platform_id platform = NULL;
    status = clGetPlatformIDs(0, NULL, &numPlatforms);
    if (status != CL_SUCCESS) {
        printf("Error: Getting Platforms. (clGetPlatformsIDs)\n");
        return FAILURE;
    }

    if (numPlatforms > 0) {
        cl_platform_id *platforms = new cl_platform_id[numPlatforms];
        status = clGetPlatformIDs(numPlatforms, platforms, NULL);
        if (status != CL_SUCCESS) {
            printf("Error: Getting Platform Ids. (clGetPlatformsIDs)\n");
            return FAILURE;
        }
        for (int i = 0; i < numPlatforms; ++i) {
            char pbuff[100];
            status = clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR,
                                       sizeof(pbuff), pbuff, NULL);
            if (status != CL_SUCCESS) {
                printf("Error: Getting Platform Info.(clGetPlatformInfo)\n");
                return FAILURE;
            }
            platform = platforms[i];
            if (!strcmp(pbuff, "Advanced Micro Devices, Inc.")) {
                break;
            }
        }
        delete platforms;
    }

    if (NULL == platform) {
        printf("NULL platform found so Exiting Application.\n");
        return FAILURE;
    }

    // 2. create context from platform
    cl_context_properties cps[3] =
        {CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 0};
    context = clCreateContextFromType(cps, CL_DEVICE_TYPE_GPU, NULL, NULL,
                                      &status);
    if (status != CL_SUCCESS) {
        printf("Error: Creating Context. (clCreateContextFromType)\n");
        return FAILURE;
    }

    // 3. Get device info
    // 3a. Get # of devices
    status = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL,
                              &deviceListSize);
    if (status != CL_SUCCESS) {
        printf("Error: Getting Context Info (1st clGetContextInfo)\n");
        return FAILURE;
    }

    // 3b. Get the device list data
    devices = (cl_device_id *)malloc(deviceListSize);
    if (devices == 0) {
        printf("Error: No devices found.\n");
        return FAILURE;
    }
    status = clGetContextInfo(context, CL_CONTEXT_DEVICES, deviceListSize,
                              devices, NULL);
    if (status != CL_SUCCESS) {
        printf("Error: Getting Context Info (2nd clGetContextInfo)\n");
        return FAILURE;
    }

    // 4. Create command queue for device
    commandQueue = clCreateCommandQueue(context, devices[0], 0, &status);
    if (status != CL_SUCCESS) {
        printf("Creating Command Queue. (clCreateCommandQueue)\n");
        return FAILURE;
    }

    const char *source = "dummy text";

    size_t sourceSize[] = {strlen(source)};

    // 5b. Register the kernel with the runtime
    program = clCreateProgramWithSource(context, 1, &source, sourceSize,
                                        &status);
    if (status != CL_SUCCESS) {
      printf("Error: Loading kernel (clCreateProgramWithSource)\n");
      return FAILURE;
    }

    status = clBuildProgram(program, 1, devices, NULL, NULL, NULL);
    if (status != CL_SUCCESS) {
        printf("Error: Building kernel (clBuildProgram)\n");
        return FAILURE;
    }

    readKernel = clCreateKernel(program, "read_kernel", &status);
    if (status != CL_SUCCESS) {
        printf("Error: Creating readKernel from program. (clCreateKernel)\n");
        return FAILURE;
    }

    return SUCCESS;
}

/* Run kernels */
int
runCLKernel(cl_kernel kernel)
{
    cl_int   status;
    cl_event event;
    size_t globalThreads[1] = {grid_size};
    size_t localThreads[1] = {work_group_size};

    // 1. Set arguments
    // 1a. code size
    size_t code_size = strlen(code);
    status = clSetKernelArg(kernel, 0, sizeof(size_t), &code_size);
    if (status != CL_SUCCESS) {
        printf("Error: Setting kernel argument. (code_size)\n");
        return FAILURE;
    }

    // 1b. code
    status = clSetKernelArg(kernel, 1, sizeof(char *), (void *)&code);
    if (status != CL_SUCCESS) {
        printf("Error: Setting kernel argument. (code_in)\n");
        return FAILURE;
    }

    // 1c. keys
    printf("keys = %p, &keys = %p, keys[0] = %d\n", keys, &keys, keys[0]);
    status = clSetKernelArg(kernel, 2, sizeof(int *), (void *)&keys);
    if (status != CL_SUCCESS) {
        printf("Error: Setting kernel argument. (key_arr)\n");
        return FAILURE;
    }

    // 1d. msg
    status = clSetKernelArg(kernel, 3, sizeof(char *), (void *)&msg);
    if (status != CL_SUCCESS) {
        printf("Error: Setting kernel argument. (memOut)\n");
        return FAILURE;
    }

    // 1e. chars_decoded
    int *chars_decoded_ptr = &chars_decoded;
    status = clSetKernelArg(kernel, 4, sizeof(int *),
                            (void *)&chars_decoded_ptr);
    if (status != CL_SUCCESS) {
        printf("Error: Setting kernel argument. (memOut)\n");
        return FAILURE;
    }

#ifdef KVM_SWITCH
    m5_switchcpu();
#endif

    // 2. Launch kernel
    status = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL,
                                    globalThreads, localThreads, 0, NULL,
                                    &event);
    if (status != CL_SUCCESS) {
        printf("Error: Enqueue failed. (clEnqueueNDRangeKernel)\n");
        return FAILURE;
    }

    // 3. Wait for the kernel
    status = clWaitForEvents(1, &event);
    if (status != CL_SUCCESS) {
        printf("Error: Waiting for kernel run to finish. (clWaitForEvents)\n");
        return FAILURE;
    }

    // 4. Cleanup
    status = clReleaseEvent(event);
    if (status != CL_SUCCESS) {
        printf("Error: Release event object. (clReleaseEvent)\n");
        return FAILURE;
    }

    return SUCCESS;
}

/* Release OpenCL resources (Context, Memory etc.) */
int
cleanupCL()
{
    cl_int status;
    status = clReleaseKernel(readKernel);
    if (status != CL_SUCCESS) {
        printf("Error: In clReleaseKernel \n");
        return FAILURE;
    }
    status = clReleaseProgram(program);
    if (status != CL_SUCCESS) {
        printf("Error: In clReleaseProgram\n");
        return FAILURE;
    }
    status = clReleaseCommandQueue(commandQueue);
    if (status != CL_SUCCESS) {
        printf("Error: In clReleaseCommandQueue\n");
        return FAILURE;
    }
    status = clReleaseContext(context);
    if (status != CL_SUCCESS) {
        printf("Error: In clReleaseContext\n");
        return FAILURE;
    }

    return SUCCESS;
}

int
main(int argc, char * argv[])
{
    // Initialize Host application
    if (setupDataStructs() != SUCCESS) {
        return FAILURE;
    }

    // Initialize OpenCL resources
    if (setupOpenCL() != SUCCESS) {
        return FAILURE;
    }

    // Run the CL program
    if (runCLKernel(readKernel) != SUCCESS) {
        return FAILURE;
    }
    printf("the gpu says:\n");
    printf("%s\n", msg);

    // Releases OpenCL resources
    if (cleanupCL()!= SUCCESS) {
        return FAILURE;
    }

    return SUCCESS;
}
<|endoftext|>


<commit_before>#include "UnrealCVPrivate.h"

class FUnrealCVPlugin : public IModuleInterface
{
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;
};

IMPLEMENT_MODULE(FUnrealCVPlugin, UnrealCV)

void FUnrealCVPlugin::StartupModule()
{

}

void FUnrealCVPlugin::ShutdownModule()
{

}<commit_msg>Start server when module loaded.<commit_after>#include "UnrealCVPrivate.h"

class FUnrealCVPlugin : public IModuleInterface
{
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;
};

IMPLEMENT_MODULE(FUnrealCVPlugin, UnrealCV)

void FUnrealCVPlugin::StartupModule()
{
	FUE4CVServer::Get().Start();
}

void FUnrealCVPlugin::ShutdownModule()
{
	// TODO: implement stop
}
<|endoftext|>


<commit_before>#include <QMessageBox>

#include "sslcomm.h"
#include "ui_sslcomm.h"

SslComm::SslComm(QWidget *parent) :
        QWidget(parent), ui(new Ui::SslComm), socket(0)
{
    ui->setupUi(this);

    ui->host->setFocus();

    connect(ui->connect, SIGNAL(clicked()), this, SLOT(changeConnectionState()));
}

SslComm::~SslComm()
{
    delete ui;
}

void SslComm::changeConnectionState()
{
    if (!socket)
    {
        // TODO create SSL socket
        socket = new QSslSocket(this);
        // TODO establish connection

        // update UI
        ui->connect->setText("&Disconnect");
    }
    else
    {
        // TODO tear down SSL connection

        // TODO remove SSL socket
        delete socket;
        socket = 0;

        // update UI
        ui->connect->setText("&Connect");
    }
}
<commit_msg>resource leak removed<commit_after>#include <QMessageBox>

#include "sslcomm.h"
#include "ui_sslcomm.h"

SslComm::SslComm(QWidget *parent) :
        QWidget(parent), ui(new Ui::SslComm), socket(0)
{
    ui->setupUi(this);

    ui->host->setFocus();

    connect(ui->connect, SIGNAL(clicked()), this, SLOT(changeConnectionState()));
}

SslComm::~SslComm()
{
    delete ui;
    if (socket)
    {
        delete socket;
    }
}

void SslComm::changeConnectionState()
{
    if (!socket)
    {
        // TODO create SSL socket
        socket = new QSslSocket(this);
        // TODO establish connection

        // update UI
        ui->connect->setText("&Disconnect");
    }
    else
    {
        // TODO tear down SSL connection

        // TODO remove SSL socket
        delete socket;
        socket = 0;

        // update UI
        ui->connect->setText("&Connect");
    }
}
<|endoftext|>