<commit_before>
#include "GuiObject.hpp"
#include "PythonHelpers.h"

int GuiObject::init(PyObject* args, PyObject* kwds) {
	// If the GuiObject type has no base set,
	// grab _GuiObject from the gui module and set it as the base.
	PyTypeObject* const selfType = &GuiObject_Type;
	if(selfType->tp_base == NULL || selfType->tp_base == &PyBaseObject_Type) {
		uninitTypeObject(selfType);

		PyObject* base = modAttrChain("gui", "_GuiObject");
		if(!base || PyErr_Occurred()) {
			if(PyErr_Occurred())
				PyErr_Print();
			Py_FatalError("Did not found gui._GuiObject.");
		}
		if(!PyClass_Check(base))
			Py_FatalError("gui._GuiObject is not a class.");
		selfType->tp_bases = PyTuple_Pack(1, base);
		Py_DECREF(base);

		if(PyType_Ready(selfType) < 0)
			Py_FatalError("Was not able to reinit type GuiObject.");
	}

	DefaultSpace = Vec(8,8);
	OuterSpace = Vec(8,8);
	return 0;
}

PyObject* Vec::asPyObject() const {
	PyObject* t = PyTuple_New(2);
	if(!t) return NULL;
	PyTuple_SET_ITEM(t, 0, PyInt_FromLong(x));
	PyTuple_SET_ITEM(t, 1, PyInt_FromLong(y));
	return t;
}

PyObject* Autoresize::asPyObject() const {
	PyObject* t = PyTuple_New(4);
	if(!t) return NULL;
	PyTuple_SET_ITEM(t, 0, PyBool_FromLong(x));
	PyTuple_SET_ITEM(t, 1, PyBool_FromLong(y));
	PyTuple_SET_ITEM(t, 2, PyBool_FromLong(w));
	PyTuple_SET_ITEM(t, 3, PyBool_FromLong(h));
	return t;
}

bool Vec::initFromPyObject(PyObject* obj) {
	if(!PyTuple_Check(obj)) {
		PyErr_Format(PyExc_ValueError, "Vec: We expect a tuple");
		return false;
	}
	if(PyTuple_GET_SIZE(obj) != 2) {
		PyErr_Format(PyExc_ValueError, "Vec: We expect a tuple with 2 elements");
		return false;
	}
	x = (int)PyInt_AsLong(PyTuple_GET_ITEM(obj, 0));
	y = (int)PyInt_AsLong(PyTuple_GET_ITEM(obj, 1));
	if(PyErr_Occurred())
		return false;
	return true;
}

bool Autoresize::initFromPyObject(PyObject* obj) {
	if(!PyTuple_Check(obj)) {
		PyErr_Format(PyExc_ValueError, "Autoresize: We expect a tuple");
		return false;
	}
	if(PyTuple_GET_SIZE(obj) != 4) {
		PyErr_Format(PyExc_ValueError, "Autoresize: We expect a tuple with 4 elements");
		return false;
	}
	x = PyObject_IsTrue(PyTuple_GET_ITEM(obj, 0));
	y = PyObject_IsTrue(PyTuple_GET_ITEM(obj, 1));
	w = PyObject_IsTrue(PyTuple_GET_ITEM(obj, 2));
	h = PyObject_IsTrue(PyTuple_GET_ITEM(obj, 3));
	if(PyErr_Occurred())
		return false;
	return true;
}

static
PyObject* guiObject_method_addChild(PyObject* _self, PyObject* _arg) {
	GuiObject* self = (GuiObject*) _self;
	if(!PyType_IsSubtype(Py_TYPE(_arg), &GuiObject_Type)) {
		PyErr_Format(PyExc_ValueError, "GuiObject.addChild: we expect a GuiObject");
		return NULL;
	}
	GuiObject* arg = (GuiObject*) _arg;
	auto func = self->meth_addChild;
	if(!func) {
		PyErr_Format(PyExc_AttributeError, "GuiObject.addChild: must be specified in subclass");
		return NULL;
	}
	Py_BEGIN_ALLOW_THREADS
	func(self, arg);
	Py_END_ALLOW_THREADS
	Py_INCREF(Py_None);
	return Py_None;
}

static PyMethodDef md_addChild = {
	"addChild",
	guiObject_method_addChild,
	METH_O,
	NULL
};

static PyObject* returnObj(PyObject* obj) {
	if(!obj) obj = Py_None;
	Py_INCREF(obj);
	return obj;
}

#define _ReturnAttr(attr) { if(strcmp(key, #attr) == 0) return returnObj(attr); }

#define _ReturnAttrVec(attr) { if(strcmp(key, #attr) == 0) return attr.asPyObject(); }

#define _ReturnCustomAttr(attr) { \
	if(strcmp(key, #attr) == 0) { \
		if(get_ ## attr == 0) { \
			PyErr_Format(PyExc_AttributeError, "GuiObject attribute '%.400s' must be specified in subclass", key); \
			return NULL; \
		} \
		PyThreadState *_save = PyEval_SaveThread(); \
		auto res = (* get_ ## attr)(this); \
		PyEval_RestoreThread(_save); \
		return res.asPyObject(); \
	} }

PyObject* GuiObject::getattr(const char* key) {
	_ReturnAttr(root);
	_ReturnAttr(parent);
	_ReturnAttr(attr);
	_ReturnAttr(nativeGuiObject);
	_ReturnAttr(subjectObject);
	_ReturnAttrVec(DefaultSpace);
	_ReturnAttrVec(OuterSpace);

	_ReturnCustomAttr(pos);
	_ReturnCustomAttr(size);
	_ReturnCustomAttr(innerSize);
	_ReturnCustomAttr(autoresize);

	if(strcmp(key, "addChild") == 0) {
		return PyCFunction_New(&md_addChild, (PyObject*) this);
	}

	if(strcmp(key, "__dict__") == 0) {
		if(!__dict__)
			__dict__ = PyDict_New();
		if(!__dict__)
			return NULL;
		return returnObj(__dict__);
	}

	// Fallthrough to generic getattr. In case we got another base type, this might work.
	PyObject* s = PyString_FromString(key);
	if(!s) return NULL;
	return PyObject_GenericGetAttr((PyObject*) this, s);
}

#define _SetAttr(attr) { \
	if(strcmp(key, #attr) == 0) { \
		attr = value; \
		Py_INCREF(value); \
		return 0; \
	} }

#define _SetAttrVec(attr) { \
	if(strcmp(key, #attr) == 0) { \
		Vec v; \
		if(!v.initFromPyObject(value)) \
			return -1; \
		attr = v; \
		return 0; \
	} }

#define _SetCustomAttr(attr, ValueType) { \
	if(strcmp(key, #attr) == 0) { \
		if(set_ ## attr == 0) { \
			PyErr_Format(PyExc_AttributeError, "GuiObject attribute '%.400s' must be specified in subclass", key); \
			return -1; \
		} \
		ValueType v; \
		if(!v.initFromPyObject(value)) \
			return -1; \
		Py_BEGIN_ALLOW_THREADS \
		(* set_ ## attr)(this, v); \
		Py_END_ALLOW_THREADS \
		return 0; \
	} }

#define _SetAttr_ErrReadOnly(attr) { \
	if(strcmp(key, #attr) == 0) { \
		PyErr_Format(PyExc_AttributeError, "GuiObject attribute '%.400s' is readonly", key); \
		return -1; \
	} }

int GuiObject::setattr(const char* key, PyObject* value) {
	_SetAttr(root);
	_SetAttr(parent);
	_SetAttr(attr);
	_SetAttr(subjectObject);
	_SetAttr(nativeGuiObject);
	_SetAttrVec(DefaultSpace);
	_SetAttrVec(OuterSpace);

	_SetCustomAttr(pos, Vec);
	_SetCustomAttr(size, Vec);
	_SetCustomAttr(autoresize, Autoresize);

	_SetAttr_ErrReadOnly(innerSize);
	_SetAttr_ErrReadOnly(addChild);

	// Fallthrough to generic setattr. In case we got another base type, this might work.
	PyObject* s = PyString_FromString(key);
	if(!s) return -1;
	int ret = PyObject_GenericSetAttr((PyObject*) this, s, value);
	Py_XDECREF(s);
	return ret;
}

<commit_msg>another readonly attr<commit_after>
#include "GuiObject.hpp"
#include "PythonHelpers.h"

int GuiObject::init(PyObject* args, PyObject* kwds) {
	// If the GuiObject type has no base set,
	// grab _GuiObject from the gui module and set it as the base.
	PyTypeObject* const selfType = &GuiObject_Type;
	if(selfType->tp_base == NULL || selfType->tp_base == &PyBaseObject_Type) {
		uninitTypeObject(selfType);

		PyObject* base = modAttrChain("gui", "_GuiObject");
		if(!base || PyErr_Occurred()) {
			if(PyErr_Occurred())
				PyErr_Print();
			Py_FatalError("Did not found gui._GuiObject.");
		}
		if(!PyClass_Check(base))
			Py_FatalError("gui._GuiObject is not a class.");
		selfType->tp_bases = PyTuple_Pack(1, base);
		Py_DECREF(base);

		if(PyType_Ready(selfType) < 0)
			Py_FatalError("Was not able to reinit type GuiObject.");
	}

	DefaultSpace = Vec(8,8);
	OuterSpace = Vec(8,8);
	return 0;
}

PyObject* Vec::asPyObject() const {
	PyObject* t = PyTuple_New(2);
	if(!t) return NULL;
	PyTuple_SET_ITEM(t, 0, PyInt_FromLong(x));
	PyTuple_SET_ITEM(t, 1, PyInt_FromLong(y));
	return t;
}

PyObject* Autoresize::asPyObject() const {
	PyObject* t = PyTuple_New(4);
	if(!t) return NULL;
	PyTuple_SET_ITEM(t, 0, PyBool_FromLong(x));
	PyTuple_SET_ITEM(t, 1, PyBool_FromLong(y));
	PyTuple_SET_ITEM(t, 2, PyBool_FromLong(w));
	PyTuple_SET_ITEM(t, 3, PyBool_FromLong(h));
	return t;
}

bool Vec::initFromPyObject(PyObject* obj) {
	if(!PyTuple_Check(obj)) {
		PyErr_Format(PyExc_ValueError, "Vec: We expect a tuple");
		return false;
	}
	if(PyTuple_GET_SIZE(obj) != 2) {
		PyErr_Format(PyExc_ValueError, "Vec: We expect a tuple with 2 elements");
		return false;
	}
	x = (int)PyInt_AsLong(PyTuple_GET_ITEM(obj, 0));
	y = (int)PyInt_AsLong(PyTuple_GET_ITEM(obj, 1));
	if(PyErr_Occurred())
		return false;
	return true;
}

bool Autoresize::initFromPyObject(PyObject* obj) {
	if(!PyTuple_Check(obj)) {
		PyErr_Format(PyExc_ValueError, "Autoresize: We expect a tuple");
		return false;
	}
	if(PyTuple_GET_SIZE(obj) != 4) {
		PyErr_Format(PyExc_ValueError, "Autoresize: We expect a tuple with 4 elements");
		return false;
	}
	x = PyObject_IsTrue(PyTuple_GET_ITEM(obj, 0));
	y = PyObject_IsTrue(PyTuple_GET_ITEM(obj, 1));
	w = PyObject_IsTrue(PyTuple_GET_ITEM(obj, 2));
	h = PyObject_IsTrue(PyTuple_GET_ITEM(obj, 3));
	if(PyErr_Occurred())
		return false;
	return true;
}

static
PyObject* guiObject_method_addChild(PyObject* _self, PyObject* _arg) {
	GuiObject* self = (GuiObject*) _self;
	if(!PyType_IsSubtype(Py_TYPE(_arg), &GuiObject_Type)) {
		PyErr_Format(PyExc_ValueError, "GuiObject.addChild: we expect a GuiObject");
		return NULL;
	}
	GuiObject* arg = (GuiObject*) _arg;
	auto func = self->meth_addChild;
	if(!func) {
		PyErr_Format(PyExc_AttributeError, "GuiObject.addChild: must be specified in subclass");
		return NULL;
	}
	Py_BEGIN_ALLOW_THREADS
	func(self, arg);
	Py_END_ALLOW_THREADS
	Py_INCREF(Py_None);
	return Py_None;
}

static PyMethodDef md_addChild = {
	"addChild",
	guiObject_method_addChild,
	METH_O,
	NULL
};

static PyObject* returnObj(PyObject* obj) {
	if(!obj) obj = Py_None;
	Py_INCREF(obj);
	return obj;
}

#define _ReturnAttr(attr) { if(strcmp(key, #attr) == 0) return returnObj(attr); }

#define _ReturnAttrVec(attr) { if(strcmp(key, #attr) == 0) return attr.asPyObject(); }

#define _ReturnCustomAttr(attr) { \
	if(strcmp(key, #attr) == 0) { \
		if(get_ ## attr == 0) { \
			PyErr_Format(PyExc_AttributeError, "GuiObject attribute '%.400s' must be specified in subclass", key); \
			return NULL; \
		} \
		PyThreadState *_save = PyEval_SaveThread(); \
		auto res = (* get_ ## attr)(this); \
		PyEval_RestoreThread(_save); \
		return res.asPyObject(); \
	} }

PyObject* GuiObject::getattr(const char* key) {
	_ReturnAttr(root);
	_ReturnAttr(parent);
	_ReturnAttr(attr);
	_ReturnAttr(nativeGuiObject);
	_ReturnAttr(subjectObject);
	_ReturnAttrVec(DefaultSpace);
	_ReturnAttrVec(OuterSpace);

	_ReturnCustomAttr(pos);
	_ReturnCustomAttr(size);
	_ReturnCustomAttr(innerSize);
	_ReturnCustomAttr(autoresize);

	if(strcmp(key, "addChild") == 0) {
		return PyCFunction_New(&md_addChild, (PyObject*) this);
	}

	if(strcmp(key, "__dict__") == 0) {
		if(!__dict__)
			__dict__ = PyDict_New();
		if(!__dict__)
			return NULL;
		return returnObj(__dict__);
	}

	// Fallthrough to generic getattr. In case we got another base type, this might work.
	PyObject* s = PyString_FromString(key);
	if(!s) return NULL;
	return PyObject_GenericGetAttr((PyObject*) this, s);
}

#define _SetAttr(attr) { \
	if(strcmp(key, #attr) == 0) { \
		attr = value; \
		Py_INCREF(value); \
		return 0; \
	} }

#define _SetAttrVec(attr) { \
	if(strcmp(key, #attr) == 0) { \
		Vec v; \
		if(!v.initFromPyObject(value)) \
			return -1; \
		attr = v; \
		return 0; \
	} }

#define _SetCustomAttr(attr, ValueType) { \
	if(strcmp(key, #attr) == 0) { \
		if(set_ ## attr == 0) { \
			PyErr_Format(PyExc_AttributeError, "GuiObject attribute '%.400s' must be specified in subclass", key); \
			return -1; \
		} \
		ValueType v; \
		if(!v.initFromPyObject(value)) \
			return -1; \
		Py_BEGIN_ALLOW_THREADS \
		(* set_ ## attr)(this, v); \
		Py_END_ALLOW_THREADS \
		return 0; \
	} }

#define _SetAttr_ErrReadOnly(attr) { \
	if(strcmp(key, #attr) == 0) { \
		PyErr_Format(PyExc_AttributeError, "GuiObject attribute '%.400s' is readonly", key); \
		return -1; \
	} }

int GuiObject::setattr(const char* key, PyObject* value) {
	_SetAttr(root);
	_SetAttr(parent);
	_SetAttr(attr);
	_SetAttr(subjectObject);
	_SetAttr(nativeGuiObject);
	_SetAttrVec(DefaultSpace);
	_SetAttrVec(OuterSpace);

	_SetCustomAttr(pos, Vec);
	_SetCustomAttr(size, Vec);
	_SetCustomAttr(autoresize, Autoresize);

	_SetAttr_ErrReadOnly(innerSize);
	_SetAttr_ErrReadOnly(addChild);
	_SetAttr_ErrReadOnly(__dict__);

	// Fallthrough to generic setattr. In case we got another base type, this might work.
	PyObject* s = PyString_FromString(key);
	if(!s) return -1;
	int ret = PyObject_GenericSetAttr((PyObject*) this, s, value);
	Py_XDECREF(s);
	return ret;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 deipi.com LLC and contributors. All rights reserved.
 *
 * 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.
 */

#include "aggregation.h"

#include <stdexcept>                        // for out_of_range

#include "aggregation_bucket.h"             // for FilterAggregation, Histog...
#include "aggregation_metric.h"             // for AGGREGATION_AVG, AGGREGAT...
#include "database_utils.h"                 // for is_valid
#include "exception.h"                      // for AggregationError, MSG_Agg...
#include "msgpack.h"                        // for MsgPack, MsgPack::const_i...
#include "schema.h"                         // for Schema
#include "stl_serialise.h"                  // for StringList

const std::unordered_map<std::string, dispatch_aggregations> map_dispatch_aggregations({
	{ AGGREGATION_COUNT,            &Aggregation::add_metric<AGGREGATION_COUNT, MetricCount>                       },
	// { AGGREGATION_CARDINALITY,      &Aggregation::add_metric<AGGREGATION_CARDINALITY, MetricCardinality>           },
	{ AGGREGATION_SUM,              &Aggregation::add_metric<AGGREGATION_SUM, MetricSum>                           },
	{ AGGREGATION_AVG,              &Aggregation::add_metric<AGGREGATION_AVG, MetricAvg>                           },
	{ AGGREGATION_MIN,              &Aggregation::add_metric<AGGREGATION_MIN, MetricMin>                           },
	{ AGGREGATION_MAX,              &Aggregation::add_metric<AGGREGATION_MAX, MetricMax>                           },
	{ AGGREGATION_VARIANCE,         &Aggregation::add_metric<AGGREGATION_VARIANCE, MetricVariance>                 },
	{ AGGREGATION_STD,              &Aggregation::add_metric<AGGREGATION_STD, MetricSTD>                           },
	{ AGGREGATION_MEDIAN,           &Aggregation::add_metric<AGGREGATION_MEDIAN, MetricMedian>                     },
	{ AGGREGATION_MODE,             &Aggregation::add_metric<AGGREGATION_MODE, MetricMode>                         },
	{ AGGREGATION_STATS,            &Aggregation::add_metric<AGGREGATION_STATS, MetricStats>                       },
	{ AGGREGATION_EXT_STATS,        &Aggregation::add_metric<AGGREGATION_EXT_STATS, MetricExtendedStats>           },
	// { AGGREGATION_GEO_BOUNDS,       &Aggregation::add_metric<AGGREGATION_GEO_BOUNDS, MetricGeoBounds>              },
	// { AGGREGATION_GEO_CENTROID,     &Aggregation::add_metric<AGGREGATION_GEO_CENTROID, MetricGeoCentroid>          },
	// { AGGREGATION_PERCENTILES,      &Aggregation::add_metric<AGGREGATION_PERCENTILES, MetricPercentiles>           },
	// { AGGREGATION_PERCENTILES_RANK, &Aggregation::add_metric<AGGREGATION_PERCENTILES_RANK, MetricPercentilesRank>  },
	// { AGGREGATION_SCRIPTED_METRIC,  &Aggregation::add_metric<AGGREGATION_SCRIPTED_METRIC, MetricScripted>          },

	{ AGGREGATION_FILTER,           &Aggregation::add_bucket<FilterAggregation>                                    },
	{ AGGREGATION_VALUE,            &Aggregation::add_bucket<ValueAggregation>                                     },
	// { AGGREGATION_DATE_HISTOGRAM,   &Aggregation::add_bucket<DateHistogramAggregation>                             },
	// { AGGREGATION_DATE_RANGE,       &Aggregation::add_bucket<DateRangeAggregation>                                 },
	// { AGGREGATION_GEO_DISTANCE,     &Aggregation::add_bucket<GeoDistanceAggregation>                               },
	// { AGGREGATION_GEO_TRIXELS,      &Aggregation::add_bucket<GeoTrixelsAggregation>                                },
	{ AGGREGATION_HISTOGRAM,        &Aggregation::add_bucket<HistogramAggregation>                                 },
	// { AGGREGATION_MISSING,          &Aggregation::add_bucket<MissingAggregation>                                   },
	{ AGGREGATION_RANGE,            &Aggregation::add_bucket<RangeAggregation>                                     },
	// { AGGREGATION_IP_RANGE,         &Aggregation::add_bucket<IPRangeAggregation>                                   },
	// { AGGREGATION_GEO_IP,           &Aggregation::add_bucket<GeoIPAggregation>                                     },
});

Aggregation::Aggregation(MsgPack& result)
	: _result(result),
	  _doc_count(0)
{
	_result[AGGREGATION_DOC_COUNT] = _doc_count;  // Initialize here so it's at the start
}

Aggregation::Aggregation(MsgPack& result, const MsgPack& conf, const std::shared_ptr<Schema>& schema)
	: _result(result),
	  _doc_count(0)
{
	_result[AGGREGATION_DOC_COUNT] = _doc_count;  // Initialize here so it's at the start

	try {
		const auto& aggs = conf.at(AGGREGATION_AGGS);
		for (const auto& agg : aggs) {
			auto sub_agg_name = agg.as_string();
			if (is_valid(sub_agg_name)) {
				const auto& sub_agg = aggs.at(sub_agg_name);
				auto sub_agg_type = (*sub_agg.begin()).as_string();
				try {
					auto func = map_dispatch_aggregations.at(sub_agg_type);
					(this->*func)(_result[sub_agg_name], sub_agg, schema);
				} catch (const std::out_of_range&) {
					THROW(AggregationError, "Aggregation type: %s is not valid", sub_agg_name.c_str());
				}
			} else {
				THROW(AggregationError, "Aggregation sub_agg_name: %s is not valid", sub_agg_name.c_str());
			}
		}
	} catch (const msgpack::type_error) {
		THROW(AggregationError, "Aggregations must be an object");
	} catch (const std::out_of_range&) { }
}

void
Aggregation::operator()(const Xapian::Document& doc)
{
	++_doc_count;
	for (auto& sub_agg : _sub_aggregations) {
		(*sub_agg)(doc);
	}
};

void
Aggregation::update()
{
	for (auto& sub_agg : _sub_aggregations) {
		sub_agg->update();
	}
	_result[AGGREGATION_DOC_COUNT] = _doc_count;
}

void
AggregationMatchSpy::operator()(const Xapian::Document& doc, double)
{
	++_total;
	_aggregation(doc);
}

Xapian::MatchSpy*
AggregationMatchSpy::clone() const
{
	return new AggregationMatchSpy(_aggs, _schema);
}

std::string
AggregationMatchSpy::name() const
{
	return "AggregationMatchSpy";
}

std::string
AggregationMatchSpy::serialise() const
{
	StringList l;
	l.push_back(_aggs.serialise());
	l.push_back(_schema->get_const_schema()->serialise());
	return l.serialise();
}

Xapian::MatchSpy*
AggregationMatchSpy::unserialise(const std::string& s, const Xapian::Registry&) const
{
	StringList l;
	l.unserialise(s);
	std::shared_ptr<const MsgPack> internal_schema = std::make_shared<const MsgPack>(MsgPack::unserialise(l.at(1)));
	return new AggregationMatchSpy(MsgPack::unserialise(l.at(0)), std::make_shared<Schema>(internal_schema));
}

std::string
AggregationMatchSpy::get_description() const
{
	std::string desc("AggregationMatchSpy(");
	desc.append(_aggs.to_string()).push_back(')');
	return desc;
}
<commit_msg>Using Serialise::STLString and Unserialise::STLString in AggregationMatchSpy<commit_after>/*
 * Copyright (C) 2016,2017 deipi.com LLC and contributors. All rights reserved.
 *
 * 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.
 */

#include "aggregation.h"

#include <stdexcept>                        // for out_of_range

#include "aggregation_bucket.h"             // for FilterAggregation, Histog...
#include "aggregation_metric.h"             // for AGGREGATION_AVG, AGGREGAT...
#include "database_utils.h"                 // for is_valid
#include "exception.h"                      // for AggregationError, MSG_Agg...
#include "msgpack.h"                        // for MsgPack, MsgPack::const_i...
#include "schema.h"                         // for Schema

const std::unordered_map<std::string, dispatch_aggregations> map_dispatch_aggregations({
	{ AGGREGATION_COUNT,            &Aggregation::add_metric<AGGREGATION_COUNT, MetricCount>                       },
	// { AGGREGATION_CARDINALITY,      &Aggregation::add_metric<AGGREGATION_CARDINALITY, MetricCardinality>           },
	{ AGGREGATION_SUM,              &Aggregation::add_metric<AGGREGATION_SUM, MetricSum>                           },
	{ AGGREGATION_AVG,              &Aggregation::add_metric<AGGREGATION_AVG, MetricAvg>                           },
	{ AGGREGATION_MIN,              &Aggregation::add_metric<AGGREGATION_MIN, MetricMin>                           },
	{ AGGREGATION_MAX,              &Aggregation::add_metric<AGGREGATION_MAX, MetricMax>                           },
	{ AGGREGATION_VARIANCE,         &Aggregation::add_metric<AGGREGATION_VARIANCE, MetricVariance>                 },
	{ AGGREGATION_STD,              &Aggregation::add_metric<AGGREGATION_STD, MetricSTD>                           },
	{ AGGREGATION_MEDIAN,           &Aggregation::add_metric<AGGREGATION_MEDIAN, MetricMedian>                     },
	{ AGGREGATION_MODE,             &Aggregation::add_metric<AGGREGATION_MODE, MetricMode>                         },
	{ AGGREGATION_STATS,            &Aggregation::add_metric<AGGREGATION_STATS, MetricStats>                       },
	{ AGGREGATION_EXT_STATS,        &Aggregation::add_metric<AGGREGATION_EXT_STATS, MetricExtendedStats>           },
	// { AGGREGATION_GEO_BOUNDS,       &Aggregation::add_metric<AGGREGATION_GEO_BOUNDS, MetricGeoBounds>              },
	// { AGGREGATION_GEO_CENTROID,     &Aggregation::add_metric<AGGREGATION_GEO_CENTROID, MetricGeoCentroid>          },
	// { AGGREGATION_PERCENTILES,      &Aggregation::add_metric<AGGREGATION_PERCENTILES, MetricPercentiles>           },
	// { AGGREGATION_PERCENTILES_RANK, &Aggregation::add_metric<AGGREGATION_PERCENTILES_RANK, MetricPercentilesRank>  },
	// { AGGREGATION_SCRIPTED_METRIC,  &Aggregation::add_metric<AGGREGATION_SCRIPTED_METRIC, MetricScripted>          },

	{ AGGREGATION_FILTER,           &Aggregation::add_bucket<FilterAggregation>                                    },
	{ AGGREGATION_VALUE,            &Aggregation::add_bucket<ValueAggregation>                                     },
	// { AGGREGATION_DATE_HISTOGRAM,   &Aggregation::add_bucket<DateHistogramAggregation>                             },
	// { AGGREGATION_DATE_RANGE,       &Aggregation::add_bucket<DateRangeAggregation>                                 },
	// { AGGREGATION_GEO_DISTANCE,     &Aggregation::add_bucket<GeoDistanceAggregation>                               },
	// { AGGREGATION_GEO_TRIXELS,      &Aggregation::add_bucket<GeoTrixelsAggregation>                                },
	{ AGGREGATION_HISTOGRAM,        &Aggregation::add_bucket<HistogramAggregation>                                 },
	// { AGGREGATION_MISSING,          &Aggregation::add_bucket<MissingAggregation>                                   },
	{ AGGREGATION_RANGE,            &Aggregation::add_bucket<RangeAggregation>                                     },
	// { AGGREGATION_IP_RANGE,         &Aggregation::add_bucket<IPRangeAggregation>                                   },
	// { AGGREGATION_GEO_IP,           &Aggregation::add_bucket<GeoIPAggregation>                                     },
});

Aggregation::Aggregation(MsgPack& result)
	: _result(result),
	  _doc_count(0)
{
	_result[AGGREGATION_DOC_COUNT] = _doc_count;  // Initialize here so it's at the start
}

Aggregation::Aggregation(MsgPack& result, const MsgPack& conf, const std::shared_ptr<Schema>& schema)
	: _result(result),
	  _doc_count(0)
{
	_result[AGGREGATION_DOC_COUNT] = _doc_count;  // Initialize here so it's at the start

	try {
		const auto& aggs = conf.at(AGGREGATION_AGGS);
		for (const auto& agg : aggs) {
			auto sub_agg_name = agg.as_string();
			if (is_valid(sub_agg_name)) {
				const auto& sub_agg = aggs.at(sub_agg_name);
				auto sub_agg_type = (*sub_agg.begin()).as_string();
				try {
					auto func = map_dispatch_aggregations.at(sub_agg_type);
					(this->*func)(_result[sub_agg_name], sub_agg, schema);
				} catch (const std::out_of_range&) {
					THROW(AggregationError, "Aggregation type: %s is not valid", sub_agg_name.c_str());
				}
			} else {
				THROW(AggregationError, "Aggregation sub_agg_name: %s is not valid", sub_agg_name.c_str());
			}
		}
	} catch (const msgpack::type_error) {
		THROW(AggregationError, "Aggregations must be an object");
	} catch (const std::out_of_range&) { }
}

void
Aggregation::operator()(const Xapian::Document& doc)
{
	++_doc_count;
	for (auto& sub_agg : _sub_aggregations) {
		(*sub_agg)(doc);
	}
};

void
Aggregation::update()
{
	for (auto& sub_agg : _sub_aggregations) {
		sub_agg->update();
	}
	_result[AGGREGATION_DOC_COUNT] = _doc_count;
}

void
AggregationMatchSpy::operator()(const Xapian::Document& doc, double)
{
	++_total;
	_aggregation(doc);
}

Xapian::MatchSpy*
AggregationMatchSpy::clone() const
{
	return new AggregationMatchSpy(_aggs, _schema);
}

std::string
AggregationMatchSpy::name() const
{
	return "AggregationMatchSpy";
}

std::string
AggregationMatchSpy::serialise() const
{
	std::vector<std::string> data = { _aggs.serialise(), _schema->get_const_schema()->serialise() };
	return Serialise::STLString(data.begin(), data.end());
}

Xapian::MatchSpy*
AggregationMatchSpy::unserialise(const std::string& s, const Xapian::Registry&) const
{
	std::vector<std::string> data;
	Unserialise::STLString(s, std::back_inserter(data));
	auto internal_schema = std::make_shared<const MsgPack>(MsgPack::unserialise(data.at(1)));
	return new AggregationMatchSpy(MsgPack::unserialise(data.at(0)), std::make_shared<Schema>(internal_schema));
}

std::string
AggregationMatchSpy::get_description() const
{
	std::string desc("AggregationMatchSpy(");
	desc.append(_aggs.to_string()).push_back(')');
	return desc;
}
<|endoftext|>


<commit_before>/*
===========================================================================

Daemon GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.

This file is part of the Daemon GPL Source Code (Daemon Source Code).

Daemon Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Daemon Source Code 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 Daemon Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Daemon Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following the
terms and conditions of the GNU General Public License which accompanied the Daemon
Source Code.  If not, please request a copy in writing from id Software at the address
below.

If you have questions concerning this license or the applicable additional terms, you
may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville,
Maryland 20850 USA.

===========================================================================
*/

#include "server.h"
#include "framework/CvarSystem.h"

/*
===============================================================================

OPERATOR CONSOLE ONLY COMMANDS

These commands can only be entered from stdin or by a remote operator datagram
===============================================================================
*/

class MapCmd: public Cmd::StaticCmd {
    public:
        MapCmd(Str::StringRef name, Str::StringRef description, bool cheat):
            Cmd::StaticCmd(name, Cmd::SYSTEM, description), cheat(cheat) {
        }

        void Run(const Cmd::Args& args) const override {
            if (args.Argc() < 2) {
                PrintUsage(args, "<mapname> (layoutname)", "loads a new map");
                return;
            }

            const std::string& mapName = args.Argv(1);

            //Make sure the map exists to avoid typos that would kill the game
            FS::GetAvailableMaps();
            const auto loadedPakInfo = FS::PakPath::LocateFile(Str::Format("maps/%s.bsp", mapName));
            if (!loadedPakInfo) {
                Print("Can't find map %s", mapName);
                return;
            }

            //Gets the layout list from the command but do not override if there is nothing
            std::string layouts = args.ConcatArgs(2);
            if (not layouts.empty()) {
                Cvar::SetValue("g_layouts", layouts);
            }

            Cvar::SetValueForce("sv_cheats", cheat ? "1" : "0");
            SV_SpawnServer(loadedPakInfo->name, mapName);
        }

        Cmd::CompletionResult Complete(int argNum, const Cmd::Args& args, Str::StringRef prefix) const override {
            if (argNum == 1) {
                Cmd::CompletionResult out;
                for (auto& map: FS::GetAvailableMaps()) {
                    if (Str::IsPrefix(prefix, map))
                        out.push_back({map, ""});
                }
                return out;
            } else if (argNum > 1) {
                return FS::HomePath::CompleteFilename(prefix, "game/layouts/" + args.Argv(1), ".dat", false, true);
            }

            return {};
        }

    private:
        bool cheat;
};
static MapCmd MapCmdRegistration("map", "starts a new map", false);
static MapCmd DevmapCmdRegistration("devmap", "starts a new map with cheats enabled", true);

void MSG_PrioritiseEntitystateFields();
void MSG_PrioritisePlayerStateFields();

static void SV_FieldInfo_f()
{
	MSG_PrioritiseEntitystateFields();
	MSG_PrioritisePlayerStateFields();
}

/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f()
{
	int         i;
	client_t    *client;
	bool    denied;
	char        reason[ MAX_STRING_CHARS ];
	bool    isBot;

	// make sure we aren't restarting twice in the same frame
	if ( com_frameTime == sv.serverId )
	{
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Log::Notice( "Server is not running.\n" );
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if ( sv_maxclients->modified )
	{
		char mapname[ MAX_QPATH ];
		char pakname[ MAX_OSPATH ];

		Log::Notice( "sv_maxclients variable change — restarting.\n" );
		// restart the map the slow way
		Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );
		Q_strncpyz( pakname, Cvar_VariableString( "pakname" ), sizeof( pakname ) );

		SV_SpawnServer(pakname, mapname);
		return;
	}

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid
	// TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) );

	// reset all the VM data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = serverState_t::SS_LOADING;
	sv.restarting = true;

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for ( i = 0; i < GAME_INIT_FRAMES; i++ )
	{
		gvm.GameRunFrame( sv.time );
		svs.time += FRAMETIME;
		sv.time += FRAMETIME;
	}

	// create a baseline for more efficient communications
	// Gordon: meh, this won't work here as the client doesn't know it has happened
//  SV_CreateBaseline ();

	sv.state = serverState_t::SS_GAME;
	sv.restarting = false;

	// connect and begin all the clients
	for ( i = 0; i < sv_maxclients->integer; i++ )
	{
		client = &svs.clients[ i ];

		// send the new gamestate to all connected clients
		if ( client->state < clientState_t::CS_CONNECTED )
		{
			continue;
		}

		isBot = SV_IsBot(client);

		// add the map_restart command
		SV_AddServerCommand( client, "map_restart\n" );

		// connect the client again, without the firstTime flag
		denied = gvm.GameClientConnect( reason, sizeof( reason ), i, false, isBot );

		if ( denied )
		{
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient( client, reason );

			if ( !isBot )
			{
				Log::Notice( "SV_MapRestart_f: dropped client %i: denied!\n", i );
			}

			continue;
		}

		client->state = clientState_t::CS_ACTIVE;

		SV_ClientEnterWorld( client, &client->lastUsercmd );
	}

	// run another frame to allow things to look at all the players
	gvm.GameRunFrame( sv.time );
	svs.time += FRAMETIME;
	sv.time += FRAMETIME;
}

class StatusCmd: public Cmd::StaticCmd
{
public:
	StatusCmd():
		StaticCmd("status", Cmd::SYSTEM, "Shows a table with server and player information")
	{}

	void Run(const Cmd::Args&) const override
	{
		// make sure server is running
		if ( !com_sv_running->integer )
		{
			Log::Notice( "Server is not running.\n" );
			return;
		}

		double cpu = ( svs.stats.latched_active + svs.stats.latched_idle );

		if ( cpu )
		{
			cpu = 100 * svs.stats.latched_active / cpu;
		}

		auto players = std::count_if(
			svs.clients,
			svs.clients+sv_maxclients->integer,
			[](const client_t& cl) {
				return cl.state != clientState_t::CS_FREE;
			}
		);

		std::string time_string;
		auto seconds = svs.time / 1000 % 60;
		auto minutes = svs.time / 1000 / 60 % 60;
		if ( auto hours = svs.time / 1000 / 60 / 60 / 60 )
		{
			time_string = Str::Format("%02d:", hours);
		}
		time_string += Str::Format("%02d:%02d", minutes, seconds);

		Print(
			"(begin server status)\n"
			"hostname: %s\n"
			"version:  %s\n"
			"protocol: %d\n"
			"cpu:      %.0f%%\n"
			"time:     %s\n"
			"map:      %s\n"
			"players:  %d / %d\n"
			"num score connection address                port   name\n"
			"--- ----- ---------- ---------------------- ------ ----",
			sv_hostname->string,
			Q3_VERSION " on " Q3_ENGINE,
			PROTOCOL_VERSION,
			cpu,
			time_string,
			sv_mapname->string,
			players,
			sv_maxclients->integer
		);

		for ( int i = 0; i < sv_maxclients->integer; i++ )
		{
			const client_t& cl = svs.clients[i];
			if ( cl.state == clientState_t::CS_FREE )
			{
				continue;
			}

			std::string connection;

			if ( cl.state == clientState_t::CS_CONNECTED )
			{
				connection = "CONNECTED";
			}
			else if ( cl.state == clientState_t::CS_ZOMBIE )
			{
				connection = "ZOMBIE";
			}
			else
			{
				connection = std::to_string(cl.ping);
				if ( connection.size() > 10 )
				{
					connection = "ERROR";
				}
			}
			OpaquePlayerState* ps = SV_GameClientNum( i );

			const char *address = NET_AdrToString( cl.netchan.remoteAddress );

			Print(
				"%3i %5i %10s %-22s %-6i %s",
				i,
				ps->persistant[ PERS_SCORE ],
				connection,
				address,
				cl.netchan.qport,
				cl.name
			);
		}

		Print( "(end server status)" );
	}
};
static StatusCmd StatusCmdRegistration;

/*
===========
SV_Serverinfo_f

Examine the serverinfo string
===========
*/
static void SV_Serverinfo_f()
{
	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Log::Notice( "Server is not running.\n" );
		return;
	}

	Log::Notice( "Server info settings:\n" );
	Info_Print( Cvar_InfoString( CVAR_SERVERINFO, false ) );
}

/*
===========
SV_Systeminfo_f

Examine the systeminfo string
===========
*/
static void SV_Systeminfo_f()
{
	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Log::Notice( "Server is not running.\n" );
		return;
	}

	Log::Notice( "System info settings:\n" );
	Info_Print( Cvar_InfoString( CVAR_SYSTEMINFO, false ) );
}

class ListMapsCmd: public Cmd::StaticCmd
{
public:
	ListMapsCmd():
		StaticCmd("listmaps", Cmd::SYSTEM, "Lists all maps available to the server")
	{}

	void Run(const Cmd::Args&) const override
	{
		auto maps = FS::GetAvailableMaps();

		Print("Listing %d maps:", maps.size());

		for ( const auto& map: maps )
		{
			Print(map.c_str());
		}
	}
};

#if BUILD_SERVER
static ListMapsCmd ListMapsCmdRegistration;
#endif

/*
==================
SV_AddOperatorCommands
==================
*/
void SV_AddOperatorCommands()
{
	if ( com_sv_running->integer )
	{
		// These commands should only be available while the server is running.
		Cmd_AddCommand( "fieldinfo",   SV_FieldInfo_f );
		Cmd_AddCommand( "heartbeat",   SV_Heartbeat_f );
		Cmd_AddCommand( "map_restart", SV_MapRestart_f );
		Cmd_AddCommand( "serverinfo",  SV_Serverinfo_f );
		Cmd_AddCommand( "systeminfo",  SV_Systeminfo_f );
	}
}

/*
==================
SV_RemoveOperatorCommands
==================
*/
void SV_RemoveOperatorCommands()
{
	Cmd_RemoveCommand( "fieldinfo" );
	Cmd_RemoveCommand( "heartbeat" );
	Cmd_RemoveCommand( "map_restart" );
	Cmd_RemoveCommand( "serverinfo" );
	Cmd_RemoveCommand( "status" );
	Cmd_RemoveCommand( "systeminfo" );
}
<commit_msg>When loading map, assume pak name map-<mapname><commit_after>/*
===========================================================================

Daemon GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.

This file is part of the Daemon GPL Source Code (Daemon Source Code).

Daemon Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Daemon Source Code 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 Daemon Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Daemon Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following the
terms and conditions of the GNU General Public License which accompanied the Daemon
Source Code.  If not, please request a copy in writing from id Software at the address
below.

If you have questions concerning this license or the applicable additional terms, you
may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville,
Maryland 20850 USA.

===========================================================================
*/

#include "server.h"
#include "framework/CvarSystem.h"

/*
===============================================================================

OPERATOR CONSOLE ONLY COMMANDS

These commands can only be entered from stdin or by a remote operator datagram
===============================================================================
*/

class MapCmd: public Cmd::StaticCmd {
    public:
        MapCmd(Str::StringRef name, Str::StringRef description, bool cheat):
            Cmd::StaticCmd(name, Cmd::SYSTEM, description), cheat(cheat) {
        }

        void Run(const Cmd::Args& args) const override {
            if (args.Argc() < 2) {
                PrintUsage(args, "<mapname> (layoutname)", "loads a new map");
                return;
            }

            const std::string& mapName = args.Argv(1);
            // For non-legacy paks, a map named "foo" must be in the pak "map-foo"
            std::string pakName;

            //Make sure the map exists to avoid typos that would kill the game
            if (FS::FindPak("map-" + mapName) != nullptr) {
                pakName = "map-" + mapName;
            } else if (FS::UseLegacyPaks()) {
                // Load all legacy paks
                for (const FS::PakInfo& pak : FS::GetAvailablePaks()) {
                    if (pak.version.empty()) {
                        std::error_code ignored;
                        FS::PakPath::LoadPakPrefix(pak, "maps/", ignored);
                    }
                }
                if (const FS::PakInfo* pak = FS::PakPath::LocateFile(Str::Format("maps/%s.bsp", mapName))) {
                    pakName = pak->name;
                }
            }

            if (pakName.empty()) {
                Print("Can't find map %s", mapName);
                return;
            }

            //Gets the layout list from the command but do not override if there is nothing
            std::string layouts = args.ConcatArgs(2);
            if (not layouts.empty()) {
                Cvar::SetValue("g_layouts", layouts);
            }

            Cvar::SetValueForce("sv_cheats", cheat ? "1" : "0");
            SV_SpawnServer(pakName, mapName);
        }

        Cmd::CompletionResult Complete(int argNum, const Cmd::Args& args, Str::StringRef prefix) const override {
            if (argNum == 1) {
                Cmd::CompletionResult out;
                for (auto& map: FS::GetAvailableMaps()) {
                    if (Str::IsPrefix(prefix, map))
                        out.push_back({map, ""});
                }
                return out;
            } else if (argNum > 1) {
                return FS::HomePath::CompleteFilename(prefix, "game/layouts/" + args.Argv(1), ".dat", false, true);
            }

            return {};
        }

    private:
        bool cheat;
};
static MapCmd MapCmdRegistration("map", "starts a new map", false);
static MapCmd DevmapCmdRegistration("devmap", "starts a new map with cheats enabled", true);

void MSG_PrioritiseEntitystateFields();
void MSG_PrioritisePlayerStateFields();

static void SV_FieldInfo_f()
{
	MSG_PrioritiseEntitystateFields();
	MSG_PrioritisePlayerStateFields();
}

/*
================
SV_MapRestart_f

Completely restarts a level, but doesn't send a new gamestate to the clients.
This allows fair starts with variable load times.
================
*/
static void SV_MapRestart_f()
{
	int         i;
	client_t    *client;
	bool    denied;
	char        reason[ MAX_STRING_CHARS ];
	bool    isBot;

	// make sure we aren't restarting twice in the same frame
	if ( com_frameTime == sv.serverId )
	{
		return;
	}

	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Log::Notice( "Server is not running.\n" );
		return;
	}

	// check for changes in variables that can't just be restarted
	// check for maxclients change
	if ( sv_maxclients->modified )
	{
		char mapname[ MAX_QPATH ];
		char pakname[ MAX_OSPATH ];

		Log::Notice( "sv_maxclients variable change — restarting.\n" );
		// restart the map the slow way
		Q_strncpyz( mapname, Cvar_VariableString( "mapname" ), sizeof( mapname ) );
		Q_strncpyz( pakname, Cvar_VariableString( "pakname" ), sizeof( pakname ) );

		SV_SpawnServer(pakname, mapname);
		return;
	}

	// toggle the server bit so clients can detect that a
	// map_restart has happened
	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;

	// generate a new serverid
	// TTimo - don't update restartedserverId there, otherwise we won't deal correctly with multiple map_restart
	sv.serverId = com_frameTime;
	Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) );

	// reset all the VM data in place without changing memory allocation
	// note that we do NOT set sv.state = SS_LOADING, so configstrings that
	// had been changed from their default values will generate broadcast updates
	sv.state = serverState_t::SS_LOADING;
	sv.restarting = true;

	SV_RestartGameProgs();

	// run a few frames to allow everything to settle
	for ( i = 0; i < GAME_INIT_FRAMES; i++ )
	{
		gvm.GameRunFrame( sv.time );
		svs.time += FRAMETIME;
		sv.time += FRAMETIME;
	}

	// create a baseline for more efficient communications
	// Gordon: meh, this won't work here as the client doesn't know it has happened
//  SV_CreateBaseline ();

	sv.state = serverState_t::SS_GAME;
	sv.restarting = false;

	// connect and begin all the clients
	for ( i = 0; i < sv_maxclients->integer; i++ )
	{
		client = &svs.clients[ i ];

		// send the new gamestate to all connected clients
		if ( client->state < clientState_t::CS_CONNECTED )
		{
			continue;
		}

		isBot = SV_IsBot(client);

		// add the map_restart command
		SV_AddServerCommand( client, "map_restart\n" );

		// connect the client again, without the firstTime flag
		denied = gvm.GameClientConnect( reason, sizeof( reason ), i, false, isBot );

		if ( denied )
		{
			// this generally shouldn't happen, because the client
			// was connected before the level change
			SV_DropClient( client, reason );

			if ( !isBot )
			{
				Log::Notice( "SV_MapRestart_f: dropped client %i: denied!\n", i );
			}

			continue;
		}

		client->state = clientState_t::CS_ACTIVE;

		SV_ClientEnterWorld( client, &client->lastUsercmd );
	}

	// run another frame to allow things to look at all the players
	gvm.GameRunFrame( sv.time );
	svs.time += FRAMETIME;
	sv.time += FRAMETIME;
}

class StatusCmd: public Cmd::StaticCmd
{
public:
	StatusCmd():
		StaticCmd("status", Cmd::SYSTEM, "Shows a table with server and player information")
	{}

	void Run(const Cmd::Args&) const override
	{
		// make sure server is running
		if ( !com_sv_running->integer )
		{
			Log::Notice( "Server is not running.\n" );
			return;
		}

		double cpu = ( svs.stats.latched_active + svs.stats.latched_idle );

		if ( cpu )
		{
			cpu = 100 * svs.stats.latched_active / cpu;
		}

		auto players = std::count_if(
			svs.clients,
			svs.clients+sv_maxclients->integer,
			[](const client_t& cl) {
				return cl.state != clientState_t::CS_FREE;
			}
		);

		std::string time_string;
		auto seconds = svs.time / 1000 % 60;
		auto minutes = svs.time / 1000 / 60 % 60;
		if ( auto hours = svs.time / 1000 / 60 / 60 / 60 )
		{
			time_string = Str::Format("%02d:", hours);
		}
		time_string += Str::Format("%02d:%02d", minutes, seconds);

		Print(
			"(begin server status)\n"
			"hostname: %s\n"
			"version:  %s\n"
			"protocol: %d\n"
			"cpu:      %.0f%%\n"
			"time:     %s\n"
			"map:      %s\n"
			"players:  %d / %d\n"
			"num score connection address                port   name\n"
			"--- ----- ---------- ---------------------- ------ ----",
			sv_hostname->string,
			Q3_VERSION " on " Q3_ENGINE,
			PROTOCOL_VERSION,
			cpu,
			time_string,
			sv_mapname->string,
			players,
			sv_maxclients->integer
		);

		for ( int i = 0; i < sv_maxclients->integer; i++ )
		{
			const client_t& cl = svs.clients[i];
			if ( cl.state == clientState_t::CS_FREE )
			{
				continue;
			}

			std::string connection;

			if ( cl.state == clientState_t::CS_CONNECTED )
			{
				connection = "CONNECTED";
			}
			else if ( cl.state == clientState_t::CS_ZOMBIE )
			{
				connection = "ZOMBIE";
			}
			else
			{
				connection = std::to_string(cl.ping);
				if ( connection.size() > 10 )
				{
					connection = "ERROR";
				}
			}
			OpaquePlayerState* ps = SV_GameClientNum( i );

			const char *address = NET_AdrToString( cl.netchan.remoteAddress );

			Print(
				"%3i %5i %10s %-22s %-6i %s",
				i,
				ps->persistant[ PERS_SCORE ],
				connection,
				address,
				cl.netchan.qport,
				cl.name
			);
		}

		Print( "(end server status)" );
	}
};
static StatusCmd StatusCmdRegistration;

/*
===========
SV_Serverinfo_f

Examine the serverinfo string
===========
*/
static void SV_Serverinfo_f()
{
	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Log::Notice( "Server is not running.\n" );
		return;
	}

	Log::Notice( "Server info settings:\n" );
	Info_Print( Cvar_InfoString( CVAR_SERVERINFO, false ) );
}

/*
===========
SV_Systeminfo_f

Examine the systeminfo string
===========
*/
static void SV_Systeminfo_f()
{
	// make sure server is running
	if ( !com_sv_running->integer )
	{
		Log::Notice( "Server is not running.\n" );
		return;
	}

	Log::Notice( "System info settings:\n" );
	Info_Print( Cvar_InfoString( CVAR_SYSTEMINFO, false ) );
}

class ListMapsCmd: public Cmd::StaticCmd
{
public:
	ListMapsCmd():
		StaticCmd("listmaps", Cmd::SYSTEM, "Lists all maps available to the server")
	{}

	void Run(const Cmd::Args&) const override
	{
		auto maps = FS::GetAvailableMaps();

		Print("Listing %d maps:", maps.size());

		for ( const auto& map: maps )
		{
			Print(map.c_str());
		}
	}
};

#if BUILD_SERVER
static ListMapsCmd ListMapsCmdRegistration;
#endif

/*
==================
SV_AddOperatorCommands
==================
*/
void SV_AddOperatorCommands()
{
	if ( com_sv_running->integer )
	{
		// These commands should only be available while the server is running.
		Cmd_AddCommand( "fieldinfo",   SV_FieldInfo_f );
		Cmd_AddCommand( "heartbeat",   SV_Heartbeat_f );
		Cmd_AddCommand( "map_restart", SV_MapRestart_f );
		Cmd_AddCommand( "serverinfo",  SV_Serverinfo_f );
		Cmd_AddCommand( "systeminfo",  SV_Systeminfo_f );
	}
}

/*
==================
SV_RemoveOperatorCommands
==================
*/
void SV_RemoveOperatorCommands()
{
	Cmd_RemoveCommand( "fieldinfo" );
	Cmd_RemoveCommand( "heartbeat" );
	Cmd_RemoveCommand( "map_restart" );
	Cmd_RemoveCommand( "serverinfo" );
	Cmd_RemoveCommand( "status" );
	Cmd_RemoveCommand( "systeminfo" );
}
<|endoftext|>


<commit_before>/* Copyright 2017 Istio 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 "src/envoy/http/mixer/filter.h"

#include "common/common/base64.h"
#include "common/protobuf/utility.h"
#include "include/istio/utils/status.h"
#include "src/envoy/http/mixer/check_data.h"
#include "src/envoy/http/mixer/report_data.h"
#include "src/envoy/utils/authn.h"
#include "src/envoy/utils/header_update.h"

using ::google::protobuf::util::Status;
using ::istio::mixer::v1::config::client::ServiceConfig;
using ::istio::mixerclient::CheckResponseInfo;

namespace Envoy {
namespace Http {
namespace Mixer {
namespace {

// Per route opaque data for "destination.service".
const std::string kPerRouteDestinationService("destination.service");
// Per route opaque data name "mixer" is base64(JSON(ServiceConfig))
const std::string kPerRouteMixer("mixer");
// Per route opaque data name "mixer_sha" is SHA(JSON(ServiceConfig))
const std::string kPerRouteMixerSha("mixer_sha");

// Read a string value from a string map.
bool ReadStringMap(const std::multimap<std::string, std::string>& string_map,
                   const std::string& name, std::string* value) {
  auto it = string_map.find(name);
  if (it != string_map.end()) {
    *value = it->second;
    return true;
  }
  return false;
}

}  // namespace

Filter::Filter(Control& control)
    : control_(control),
      state_(NotStarted),
      initiating_call_(false),
      headers_(nullptr) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {}", __func__);
}

void Filter::ReadPerRouteConfig(
    const Router::RouteEntry* entry,
    ::istio::control::http::Controller::PerRouteConfig* config) {
  if (entry == nullptr) {
    return;
  }

  // Check v2 per-route config.
  auto route_cfg = entry->perFilterConfigTyped<PerRouteServiceConfig>("mixer");
  if (route_cfg) {
    if (!control_.controller()->LookupServiceConfig(route_cfg->hash)) {
      control_.controller()->AddServiceConfig(route_cfg->hash,
                                              route_cfg->config);
    }
    config->service_config_id = route_cfg->hash;
    return;
  }

  const auto& string_map = entry->opaqueConfig();
  ReadStringMap(string_map, kPerRouteDestinationService,
                &config->destination_service);

  if (!ReadStringMap(string_map, kPerRouteMixerSha,
                     &config->service_config_id) ||
      config->service_config_id.empty()) {
    return;
  }

  if (control_.controller()->LookupServiceConfig(config->service_config_id)) {
    return;
  }

  std::string config_base64;
  if (!ReadStringMap(string_map, kPerRouteMixer, &config_base64)) {
    ENVOY_LOG(warn, "Service {} missing [mixer] per-route attribute",
              config->destination_service);
    return;
  }
  std::string config_json = Base64::decode(config_base64);
  if (config_json.empty()) {
    ENVOY_LOG(warn, "Service {} invalid base64 config data",
              config->destination_service);
    return;
  }
  ServiceConfig config_pb;
  auto status = Utils::ParseJsonMessage(config_json, &config_pb);
  if (!status.ok()) {
    ENVOY_LOG(warn,
              "Service {} failed to convert JSON config to protobuf, error: {}",
              config->destination_service, status.ToString());
    return;
  }
  control_.controller()->AddServiceConfig(config->service_config_id, config_pb);
  ENVOY_LOG(info, "Service {}, config_id {}, config: {}",
            config->destination_service, config->service_config_id,
            MessageUtil::getJsonStringFromMessage(config_pb, true));
}

FilterHeadersStatus Filter::decodeHeaders(HeaderMap& headers, bool) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {}", __func__);
  request_total_size_ += headers.byteSize();

  ::istio::control::http::Controller::PerRouteConfig config;
  auto route = decoder_callbacks_->route();
  if (route) {
    ReadPerRouteConfig(route->routeEntry(), &config);
  }
  handler_ = control_.controller()->CreateRequestHandler(config);

  state_ = Calling;
  initiating_call_ = true;
  CheckData check_data(headers,
                       decoder_callbacks_->requestInfo().dynamicMetadata(),
                       decoder_callbacks_->connection());
  Utils::HeaderUpdate header_update(&headers);
  headers_ = &headers;
  cancel_check_ = handler_->Check(
      &check_data, &header_update,
      control_.GetCheckTransport(decoder_callbacks_->activeSpan()),
      [this](const CheckResponseInfo& info) { completeCheck(info); });
  initiating_call_ = false;

  if (state_ == Complete) {
    return FilterHeadersStatus::Continue;
  }
  ENVOY_LOG(debug, "Called Mixer::Filter : {} Stop", __func__);
  return FilterHeadersStatus::StopIteration;
}

FilterDataStatus Filter::decodeData(Buffer::Instance& data, bool end_stream) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {} ({}, {})", __func__,
            data.length(), end_stream);
  request_total_size_ += data.length();
  if (state_ == Calling) {
    return FilterDataStatus::StopIterationAndWatermark;
  }
  return FilterDataStatus::Continue;
}

FilterTrailersStatus Filter::decodeTrailers(HeaderMap& trailers) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {}", __func__);
  request_total_size_ += trailers.byteSize();
  if (state_ == Calling) {
    return FilterTrailersStatus::StopIteration;
  }
  return FilterTrailersStatus::Continue;
}

void Filter::UpdateHeaders(
    HeaderMap& headers, const ::google::protobuf::RepeatedPtrField<
                            ::istio::mixer::v1::HeaderOperation>& operations) {
  for (auto const iter : operations) {
    switch (iter.operation()) {
      case ::istio::mixer::v1::HeaderOperation_Operation_REPLACE:
        headers.remove(LowerCaseString(iter.name()));
        headers.addCopy(LowerCaseString(iter.name()), iter.value());
        break;
      case ::istio::mixer::v1::HeaderOperation_Operation_REMOVE:
        headers.remove(LowerCaseString(iter.name()));
        break;
      case ::istio::mixer::v1::HeaderOperation_Operation_APPEND:
        headers.addCopy(LowerCaseString(iter.name()), iter.value());
        break;
      default:
        PANIC("unreachable header operation");
    }
  }
}

FilterHeadersStatus Filter::encodeHeaders(HeaderMap& headers, bool) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {} {}", __func__, state_);
  // Init state is possible if a filter prior to mixerfilter interrupts the
  // filter chain
  ASSERT(state_ == NotStarted || state_ == Complete || state_ == Responded);
  if (state_ == Complete) {
    // handle response header operations
    UpdateHeaders(headers, route_directive_.response_header_operations());
  }
  return FilterHeadersStatus::Continue;
}

void Filter::setDecoderFilterCallbacks(
    StreamDecoderFilterCallbacks& callbacks) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {}", __func__);
  decoder_callbacks_ = &callbacks;
}

void Filter::completeCheck(const CheckResponseInfo& info) {
  auto status = info.response_status;
  ENVOY_LOG(debug, "Called Mixer::Filter : check complete {}",
            status.ToString());
  // This stream has been reset, abort the callback.
  if (state_ == Responded) {
    return;
  }

  if (!status.ok()) {
    state_ = Responded;
    int status_code = ::istio::utils::StatusHttpCode(status.error_code());
    decoder_callbacks_->sendLocalReply(Code(status_code), status.ToString(),
                                       nullptr);
    decoder_callbacks_->requestInfo().setResponseFlag(
        RequestInfo::ResponseFlag::UnauthorizedExternalService);
    return;
  }

  state_ = Complete;
  route_directive_ = info.route_directive;

  // handle direct response from the route directive
  if (status.ok() && route_directive_.direct_response_code() != 0) {
    ENVOY_LOG(debug, "Mixer::Filter direct response");
    state_ = Responded;
    decoder_callbacks_->sendLocalReply(
        Code(route_directive_.direct_response_code()),
        route_directive_.direct_response_body(), [this](HeaderMap& headers) {
          UpdateHeaders(headers, route_directive_.response_header_operations());
        });
    return;
  }

  // handle request header operations
  if (nullptr != headers_) {
    UpdateHeaders(*headers_, route_directive_.request_header_operations());
    headers_ = nullptr;
  }

  if (!initiating_call_) {
    decoder_callbacks_->continueDecoding();
  }
}

void Filter::onDestroy() {
  ENVOY_LOG(debug, "Called Mixer::Filter : {} state: {}", __func__, state_);
  if (state_ != Calling) {
    cancel_check_ = nullptr;
  }
  state_ = Responded;
  if (cancel_check_) {
    ENVOY_LOG(debug, "Cancelling check call");
    cancel_check_();
    cancel_check_ = nullptr;
  }
}

void Filter::log(const HeaderMap* request_headers,
                 const HeaderMap* response_headers,
                 const HeaderMap* response_trailers,
                 const RequestInfo::RequestInfo& request_info) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {}", __func__);
  if (!handler_) {
    if (request_headers == nullptr) {
      return;
    }

    // Here Request is rejected by other filters, Mixer filter is not called.
    ::istio::control::http::Controller::PerRouteConfig config;
    ReadPerRouteConfig(request_info.routeEntry(), &config);
    handler_ = control_.controller()->CreateRequestHandler(config);

    CheckData check_data(*request_headers, request_info.dynamicMetadata(),
                         nullptr);
    handler_->ExtractRequestAttributes(&check_data);
  }
  // response trailer header is not counted to response total size.
  ReportData report_data(response_headers, response_trailers, request_info,
                         request_total_size_);
  handler_->Report(&report_data);
}

}  // namespace Mixer
}  // namespace Http
}  // namespace Envoy
<commit_msg>mixer: clear route cache on header update (#1946)<commit_after>/* Copyright 2017 Istio 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 "src/envoy/http/mixer/filter.h"

#include "common/common/base64.h"
#include "common/protobuf/utility.h"
#include "include/istio/utils/status.h"
#include "src/envoy/http/mixer/check_data.h"
#include "src/envoy/http/mixer/report_data.h"
#include "src/envoy/utils/authn.h"
#include "src/envoy/utils/header_update.h"

using ::google::protobuf::util::Status;
using ::istio::mixer::v1::config::client::ServiceConfig;
using ::istio::mixerclient::CheckResponseInfo;

namespace Envoy {
namespace Http {
namespace Mixer {
namespace {

// Per route opaque data for "destination.service".
const std::string kPerRouteDestinationService("destination.service");
// Per route opaque data name "mixer" is base64(JSON(ServiceConfig))
const std::string kPerRouteMixer("mixer");
// Per route opaque data name "mixer_sha" is SHA(JSON(ServiceConfig))
const std::string kPerRouteMixerSha("mixer_sha");

// Read a string value from a string map.
bool ReadStringMap(const std::multimap<std::string, std::string>& string_map,
                   const std::string& name, std::string* value) {
  auto it = string_map.find(name);
  if (it != string_map.end()) {
    *value = it->second;
    return true;
  }
  return false;
}

}  // namespace

Filter::Filter(Control& control)
    : control_(control),
      state_(NotStarted),
      initiating_call_(false),
      headers_(nullptr) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {}", __func__);
}

void Filter::ReadPerRouteConfig(
    const Router::RouteEntry* entry,
    ::istio::control::http::Controller::PerRouteConfig* config) {
  if (entry == nullptr) {
    return;
  }

  // Check v2 per-route config.
  auto route_cfg = entry->perFilterConfigTyped<PerRouteServiceConfig>("mixer");
  if (route_cfg) {
    if (!control_.controller()->LookupServiceConfig(route_cfg->hash)) {
      control_.controller()->AddServiceConfig(route_cfg->hash,
                                              route_cfg->config);
    }
    config->service_config_id = route_cfg->hash;
    return;
  }

  const auto& string_map = entry->opaqueConfig();
  ReadStringMap(string_map, kPerRouteDestinationService,
                &config->destination_service);

  if (!ReadStringMap(string_map, kPerRouteMixerSha,
                     &config->service_config_id) ||
      config->service_config_id.empty()) {
    return;
  }

  if (control_.controller()->LookupServiceConfig(config->service_config_id)) {
    return;
  }

  std::string config_base64;
  if (!ReadStringMap(string_map, kPerRouteMixer, &config_base64)) {
    ENVOY_LOG(warn, "Service {} missing [mixer] per-route attribute",
              config->destination_service);
    return;
  }
  std::string config_json = Base64::decode(config_base64);
  if (config_json.empty()) {
    ENVOY_LOG(warn, "Service {} invalid base64 config data",
              config->destination_service);
    return;
  }
  ServiceConfig config_pb;
  auto status = Utils::ParseJsonMessage(config_json, &config_pb);
  if (!status.ok()) {
    ENVOY_LOG(warn,
              "Service {} failed to convert JSON config to protobuf, error: {}",
              config->destination_service, status.ToString());
    return;
  }
  control_.controller()->AddServiceConfig(config->service_config_id, config_pb);
  ENVOY_LOG(info, "Service {}, config_id {}, config: {}",
            config->destination_service, config->service_config_id,
            MessageUtil::getJsonStringFromMessage(config_pb, true));
}

FilterHeadersStatus Filter::decodeHeaders(HeaderMap& headers, bool) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {}", __func__);
  request_total_size_ += headers.byteSize();

  ::istio::control::http::Controller::PerRouteConfig config;
  auto route = decoder_callbacks_->route();
  if (route) {
    ReadPerRouteConfig(route->routeEntry(), &config);
  }
  handler_ = control_.controller()->CreateRequestHandler(config);

  state_ = Calling;
  initiating_call_ = true;
  CheckData check_data(headers,
                       decoder_callbacks_->requestInfo().dynamicMetadata(),
                       decoder_callbacks_->connection());
  Utils::HeaderUpdate header_update(&headers);
  headers_ = &headers;
  cancel_check_ = handler_->Check(
      &check_data, &header_update,
      control_.GetCheckTransport(decoder_callbacks_->activeSpan()),
      [this](const CheckResponseInfo& info) { completeCheck(info); });
  initiating_call_ = false;

  if (state_ == Complete) {
    return FilterHeadersStatus::Continue;
  }
  ENVOY_LOG(debug, "Called Mixer::Filter : {} Stop", __func__);
  return FilterHeadersStatus::StopIteration;
}

FilterDataStatus Filter::decodeData(Buffer::Instance& data, bool end_stream) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {} ({}, {})", __func__,
            data.length(), end_stream);
  request_total_size_ += data.length();
  if (state_ == Calling) {
    return FilterDataStatus::StopIterationAndWatermark;
  }
  return FilterDataStatus::Continue;
}

FilterTrailersStatus Filter::decodeTrailers(HeaderMap& trailers) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {}", __func__);
  request_total_size_ += trailers.byteSize();
  if (state_ == Calling) {
    return FilterTrailersStatus::StopIteration;
  }
  return FilterTrailersStatus::Continue;
}

void Filter::UpdateHeaders(
    HeaderMap& headers, const ::google::protobuf::RepeatedPtrField<
                            ::istio::mixer::v1::HeaderOperation>& operations) {
  for (auto const iter : operations) {
    switch (iter.operation()) {
      case ::istio::mixer::v1::HeaderOperation_Operation_REPLACE:
        headers.remove(LowerCaseString(iter.name()));
        headers.addCopy(LowerCaseString(iter.name()), iter.value());
        break;
      case ::istio::mixer::v1::HeaderOperation_Operation_REMOVE:
        headers.remove(LowerCaseString(iter.name()));
        break;
      case ::istio::mixer::v1::HeaderOperation_Operation_APPEND:
        headers.addCopy(LowerCaseString(iter.name()), iter.value());
        break;
      default:
        PANIC("unreachable header operation");
    }
  }
}

FilterHeadersStatus Filter::encodeHeaders(HeaderMap& headers, bool) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {} {}", __func__, state_);
  // Init state is possible if a filter prior to mixerfilter interrupts the
  // filter chain
  ASSERT(state_ == NotStarted || state_ == Complete || state_ == Responded);
  if (state_ == Complete) {
    // handle response header operations
    UpdateHeaders(headers, route_directive_.response_header_operations());
  }
  return FilterHeadersStatus::Continue;
}

void Filter::setDecoderFilterCallbacks(
    StreamDecoderFilterCallbacks& callbacks) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {}", __func__);
  decoder_callbacks_ = &callbacks;
}

void Filter::completeCheck(const CheckResponseInfo& info) {
  auto status = info.response_status;
  ENVOY_LOG(debug, "Called Mixer::Filter : check complete {}",
            status.ToString());
  // This stream has been reset, abort the callback.
  if (state_ == Responded) {
    return;
  }

  if (!status.ok()) {
    state_ = Responded;
    int status_code = ::istio::utils::StatusHttpCode(status.error_code());
    decoder_callbacks_->sendLocalReply(Code(status_code), status.ToString(),
                                       nullptr);
    decoder_callbacks_->requestInfo().setResponseFlag(
        RequestInfo::ResponseFlag::UnauthorizedExternalService);
    return;
  }

  state_ = Complete;
  route_directive_ = info.route_directive;

  // handle direct response from the route directive
  if (status.ok() && route_directive_.direct_response_code() != 0) {
    ENVOY_LOG(debug, "Mixer::Filter direct response");
    state_ = Responded;
    decoder_callbacks_->sendLocalReply(
        Code(route_directive_.direct_response_code()),
        route_directive_.direct_response_body(), [this](HeaderMap& headers) {
          UpdateHeaders(headers, route_directive_.response_header_operations());
        });
    return;
  }

  // handle request header operations
  if (nullptr != headers_) {
    UpdateHeaders(*headers_, route_directive_.request_header_operations());
    headers_ = nullptr;
    if (route_directive_.request_header_operations().size() > 0) {
      decoder_callbacks_->clearRouteCache();
    }
  }

  if (!initiating_call_) {
    decoder_callbacks_->continueDecoding();
  }
}

void Filter::onDestroy() {
  ENVOY_LOG(debug, "Called Mixer::Filter : {} state: {}", __func__, state_);
  if (state_ != Calling) {
    cancel_check_ = nullptr;
  }
  state_ = Responded;
  if (cancel_check_) {
    ENVOY_LOG(debug, "Cancelling check call");
    cancel_check_();
    cancel_check_ = nullptr;
  }
}

void Filter::log(const HeaderMap* request_headers,
                 const HeaderMap* response_headers,
                 const HeaderMap* response_trailers,
                 const RequestInfo::RequestInfo& request_info) {
  ENVOY_LOG(debug, "Called Mixer::Filter : {}", __func__);
  if (!handler_) {
    if (request_headers == nullptr) {
      return;
    }

    // Here Request is rejected by other filters, Mixer filter is not called.
    ::istio::control::http::Controller::PerRouteConfig config;
    ReadPerRouteConfig(request_info.routeEntry(), &config);
    handler_ = control_.controller()->CreateRequestHandler(config);

    CheckData check_data(*request_headers, request_info.dynamicMetadata(),
                         nullptr);
    handler_->ExtractRequestAttributes(&check_data);
  }
  // response trailer header is not counted to response total size.
  ReportData report_data(response_headers, response_trailers, request_info,
                         request_total_size_);
  handler_->Report(&report_data);
}

}  // namespace Mixer
}  // namespace Http
}  // namespace Envoy
<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "ThermalContactAction.h"

#include "AddVariableAction.h"
#include "FEProblem.h"
#include "libmesh/string_to_enum.h"
#include "GapConductance.h"
#include "NonlinearSystem.h"

registerMooseAction("HeatConductionApp", ThermalContactAction, "add_aux_kernel");
registerMooseAction("HeatConductionApp", ThermalContactAction, "add_aux_variable");
registerMooseAction("HeatConductionApp", ThermalContactAction, "add_bc");
registerMooseAction("HeatConductionApp", ThermalContactAction, "add_dirac_kernel");
registerMooseAction("HeatConductionApp", ThermalContactAction, "add_material");
registerMooseAction("HeatConductionApp", ThermalContactAction, "add_slave_flux_vector");

template <>
InputParameters
validParams<ThermalContactAction>()
{
  InputParameters params = validParams<Action>();
  params.addClassDescription(
      "Action that controls the creation of all of the necessary objects for "
      "calculation of Thermal Contact");

  params.addParam<std::string>(
      "gap_aux_type",
      "GapValueAux",
      "A string representing the Moose object that will be used for computing the gap size");
  params.addRequiredParam<NonlinearVariableName>("variable", "The variable for thermal contact");
  params.addRequiredParam<BoundaryName>("master", "The master surface");
  params.addRequiredParam<BoundaryName>("slave", "The slave surface");
  params.addParam<Real>("tangential_tolerance",
                        "Tangential distance to extend edges of contact surfaces");
  params.addParam<Real>(
      "normal_smoothing_distance",
      "Distance from edge in parametric coordinates over which to smooth contact normal");
  params.addParam<std::string>("normal_smoothing_method",
                               "Method to use to smooth normals (edge_based|nodal_normal_based)");

  MooseEnum orders(AddVariableAction::getNonlinearVariableOrders());
  params.addParam<MooseEnum>("order", orders, "The finite element order");

  params.addParam<bool>(
      "warnings", false, "Whether to output warning messages concerning nodes not being found");
  params.addParam<bool>(
      "quadrature", false, "Whether or not to use quadrature point based gap heat transfer");

  params.addParam<std::string>(
      "appended_property_name", "", "Name appended to material properties to make them unique");
  params.addRequiredParam<std::string>(
      "type",
      "A string representing the Moose object that will be used for heat conduction over the gap");

  params.addParam<std::vector<VariableName>>("disp_x", "The x displacement");
  params.addParam<std::vector<VariableName>>("disp_y", "The y displacement");
  params.addParam<std::vector<VariableName>>("disp_z", "The z displacement");
  params.addParam<std::vector<VariableName>>(
      "displacements",
      "The displacements appropriate for the simulation geometry and coordinate system");

  params.addParam<std::vector<AuxVariableName>>(
      "save_in", "The Auxiliary Variable to (optionally) save the boundary flux in");
  params.addParam<Real>("gap_conductivity", 1.0, "The thermal conductivity of the gap material");
  params.addParam<FunctionName>(
      "gap_conductivity_function",
      "Thermal conductivity of the gap material as a function.  Multiplied by gap_conductivity.");
  params.addParam<std::vector<VariableName>>(
      "gap_conductivity_function_variable",
      "Variable to be used in gap_conductivity_function in place of time");

  params += GapConductance::actionParameters();

  return params;
}

ThermalContactAction::ThermalContactAction(const InputParameters & params)
  : Action(params),
    _quadrature(getParam<bool>("quadrature")),
    _order(getParam<MooseEnum>("order")),
    _penetration_var_name(_quadrature ? "qpoint_penetration" : "penetration"),
    _gap_value_name("paired_" + getParam<NonlinearVariableName>("variable")),
    _gap_conductivity_name("paired_k_" + getParam<NonlinearVariableName>("variable"))
{
}

void
ThermalContactAction::act()
{
  if (_current_task == "add_aux_kernel")
    addAuxKernels();
  else if (_current_task == "add_aux_variable")
    addAuxVariables();
  else if (_current_task == "add_bc")
    addBCs();
  else if (_current_task == "add_dirac_kernel")
    addDiracKernels();
  else if (_current_task == "add_material")
    addMaterials();
  else if (_current_task == "add_slave_flux_vector")
    addSlaveFluxVector();
}

void
ThermalContactAction::addAuxKernels()
{
  // Add gap aux kernel
  {
    InputParameters params = _factory.getValidParams(getParam<std::string>("gap_aux_type"));

    params.applySpecificParameters(
        parameters(),
        {"tangential_tolerance", "normal_smoothing_distance", "normal_smoothing_method", "order"});
    params.set<AuxVariableName>("variable") = _gap_value_name;
    params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
    params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("slave")};
    params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("master");
    params.set<VariableName>("paired_variable") = getParam<NonlinearVariableName>("variable");

    _problem->addAuxKernel(getParam<std::string>("gap_aux_type"), "gap_value_" + name(), params);

    if (_quadrature)
    {
      params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("master")};
      params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("slave");

      _problem->addAuxKernel(
          getParam<std::string>("gap_aux_type"), "gap_value_master_" + name(), params);
    }
  }

  // Add penetration aux kernel
  {
    InputParameters params = _factory.getValidParams("PenetrationAux");

    params.applySpecificParameters(
        parameters(),
        {"tangential_tolerance", "normal_smoothing_distance", "normal_smoothing_method", "order"});
    params.set<AuxVariableName>("variable") = _penetration_var_name;
    params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
    params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("slave")};
    params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("master");

    _problem->addAuxKernel("PenetrationAux", "penetration_" + name(), params);
  }
}

void
ThermalContactAction::addAuxVariables()
{
  // We need to add variables only once per variable name.  However, we don't know how many unique
  // variable names we will have.  So, we'll always add them.

  MooseEnum order = getParam<MooseEnum>("order");
  std::string family = "LAGRANGE";

  if (_quadrature)
  {
    order = "CONSTANT";
    family = "MONOMIAL";
  }

  _problem->addAuxVariable(_penetration_var_name,
                           FEType(order, Utility::string_to_enum<FEFamily>(family)));

  _problem->addAuxVariable(_gap_value_name,
                           FEType(order, Utility::string_to_enum<FEFamily>(family)));
}

void
ThermalContactAction::addBCs()
{
  const std::string object_name = getParam<std::string>("type");
  InputParameters params = _factory.getValidParams(object_name);
  params.applyParameters(parameters());

  if (_quadrature)
  {
    params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("master");
    params.set<bool>("use_displaced_mesh") = true;
  }
  else
  {
    params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
    params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
  }

  params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("slave")};

  _problem->addBoundaryCondition(object_name, "gap_bc_" + name(), params);

  if (_quadrature)
  {
    // Swap master and slave for this one
    params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("master")};
    params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("slave");

    _problem->addBoundaryCondition(object_name, "gap_bc_master_" + name(), params);
  }
}

void
ThermalContactAction::addDiracKernels()
{
  if (_quadrature)
    return;

  const std::string object_name = "GapHeatPointSourceMaster";
  InputParameters params = _factory.getValidParams(object_name);
  params.applySpecificParameters(parameters(),
                                 {"tangential_tolerance",
                                  "normal_smoothing_distance",
                                  "normal_smoothing_method",
                                  "order",
                                  "slave",
                                  "variable"});
  params.set<BoundaryName>("boundary") = getParam<BoundaryName>("master");

  _problem->addDiracKernel(object_name, object_name + "_" + name(), params);
}

void
ThermalContactAction::addMaterials()
{
  if (getParam<std::string>("type") != "GapHeatTransfer")
    return;

  const std::string object_type = "GapConductance";

  InputParameters params = _factory.getValidParams(object_type);
  params.applyParameters(parameters(), {"variable"});

  params.set<std::vector<VariableName>>("variable") = {getParam<NonlinearVariableName>("variable")};
  params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("slave")};

  if (_quadrature)
  {
    params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("master");
  }
  else
  {
    params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
    params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
  }

  _problem->addMaterial(object_type, name() + "_" + "gap_value", params);

  if (_quadrature)
  {
    params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("slave");
    params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("master")};

    _problem->addMaterial(object_type, name() + "_" + "gap_value_master", params);
  }
}

void
ThermalContactAction::addSlaveFluxVector()
{
  _problem->getNonlinearSystemBase().addVector("slave_flux", false, GHOSTED);
  _problem->getNonlinearSystemBase().zeroVectorForResidual("slave_flux");

  // It is risky to apply this optimization to contact problems
  // since the problem configuration may be changed during Jacobian
  // evaluation. We therefore turn it off for all contact problems so that
  // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3 or older.
  if (!_problem->isSNESMFReuseBaseSetbyUser())
    _problem->setSNESMFReuseBase(false, false);
}
<commit_msg>Passed warnings to GapValueAux (#12959)<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "ThermalContactAction.h"

#include "AddVariableAction.h"
#include "FEProblem.h"
#include "libmesh/string_to_enum.h"
#include "GapConductance.h"
#include "NonlinearSystem.h"

registerMooseAction("HeatConductionApp", ThermalContactAction, "add_aux_kernel");
registerMooseAction("HeatConductionApp", ThermalContactAction, "add_aux_variable");
registerMooseAction("HeatConductionApp", ThermalContactAction, "add_bc");
registerMooseAction("HeatConductionApp", ThermalContactAction, "add_dirac_kernel");
registerMooseAction("HeatConductionApp", ThermalContactAction, "add_material");
registerMooseAction("HeatConductionApp", ThermalContactAction, "add_slave_flux_vector");

template <>
InputParameters
validParams<ThermalContactAction>()
{
  InputParameters params = validParams<Action>();
  params.addClassDescription(
      "Action that controls the creation of all of the necessary objects for "
      "calculation of Thermal Contact");

  params.addParam<std::string>(
      "gap_aux_type",
      "GapValueAux",
      "A string representing the Moose object that will be used for computing the gap size");
  params.addRequiredParam<NonlinearVariableName>("variable", "The variable for thermal contact");
  params.addRequiredParam<BoundaryName>("master", "The master surface");
  params.addRequiredParam<BoundaryName>("slave", "The slave surface");
  params.addParam<Real>("tangential_tolerance",
                        "Tangential distance to extend edges of contact surfaces");
  params.addParam<Real>(
      "normal_smoothing_distance",
      "Distance from edge in parametric coordinates over which to smooth contact normal");
  params.addParam<std::string>("normal_smoothing_method",
                               "Method to use to smooth normals (edge_based|nodal_normal_based)");

  MooseEnum orders(AddVariableAction::getNonlinearVariableOrders());
  params.addParam<MooseEnum>("order", orders, "The finite element order");

  params.addParam<bool>(
      "warnings", false, "Whether to output warning messages concerning nodes not being found");
  params.addParam<bool>(
      "quadrature", false, "Whether or not to use quadrature point based gap heat transfer");

  params.addParam<std::string>(
      "appended_property_name", "", "Name appended to material properties to make them unique");
  params.addRequiredParam<std::string>(
      "type",
      "A string representing the Moose object that will be used for heat conduction over the gap");

  params.addParam<std::vector<VariableName>>("disp_x", "The x displacement");
  params.addParam<std::vector<VariableName>>("disp_y", "The y displacement");
  params.addParam<std::vector<VariableName>>("disp_z", "The z displacement");
  params.addParam<std::vector<VariableName>>(
      "displacements",
      "The displacements appropriate for the simulation geometry and coordinate system");

  params.addParam<std::vector<AuxVariableName>>(
      "save_in", "The Auxiliary Variable to (optionally) save the boundary flux in");
  params.addParam<Real>("gap_conductivity", 1.0, "The thermal conductivity of the gap material");
  params.addParam<FunctionName>(
      "gap_conductivity_function",
      "Thermal conductivity of the gap material as a function.  Multiplied by gap_conductivity.");
  params.addParam<std::vector<VariableName>>(
      "gap_conductivity_function_variable",
      "Variable to be used in gap_conductivity_function in place of time");

  params += GapConductance::actionParameters();

  return params;
}

ThermalContactAction::ThermalContactAction(const InputParameters & params)
  : Action(params),
    _quadrature(getParam<bool>("quadrature")),
    _order(getParam<MooseEnum>("order")),
    _penetration_var_name(_quadrature ? "qpoint_penetration" : "penetration"),
    _gap_value_name("paired_" + getParam<NonlinearVariableName>("variable")),
    _gap_conductivity_name("paired_k_" + getParam<NonlinearVariableName>("variable"))
{
}

void
ThermalContactAction::act()
{
  if (_current_task == "add_aux_kernel")
    addAuxKernels();
  else if (_current_task == "add_aux_variable")
    addAuxVariables();
  else if (_current_task == "add_bc")
    addBCs();
  else if (_current_task == "add_dirac_kernel")
    addDiracKernels();
  else if (_current_task == "add_material")
    addMaterials();
  else if (_current_task == "add_slave_flux_vector")
    addSlaveFluxVector();
}

void
ThermalContactAction::addAuxKernels()
{
  // Add gap aux kernel
  {
    InputParameters params = _factory.getValidParams(getParam<std::string>("gap_aux_type"));

    params.applySpecificParameters(parameters(),
                                   {"tangential_tolerance",
                                    "normal_smoothing_distance",
                                    "normal_smoothing_method",
                                    "order",
                                    "warnings"});
    params.set<AuxVariableName>("variable") = _gap_value_name;
    params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
    params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("slave")};
    params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("master");
    params.set<VariableName>("paired_variable") = getParam<NonlinearVariableName>("variable");

    _problem->addAuxKernel(getParam<std::string>("gap_aux_type"), "gap_value_" + name(), params);

    if (_quadrature)
    {
      params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("master")};
      params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("slave");

      _problem->addAuxKernel(
          getParam<std::string>("gap_aux_type"), "gap_value_master_" + name(), params);
    }
  }

  // Add penetration aux kernel
  {
    InputParameters params = _factory.getValidParams("PenetrationAux");

    params.applySpecificParameters(
        parameters(),
        {"tangential_tolerance", "normal_smoothing_distance", "normal_smoothing_method", "order"});
    params.set<AuxVariableName>("variable") = _penetration_var_name;
    params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
    params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("slave")};
    params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("master");

    _problem->addAuxKernel("PenetrationAux", "penetration_" + name(), params);
  }
}

void
ThermalContactAction::addAuxVariables()
{
  // We need to add variables only once per variable name.  However, we don't know how many unique
  // variable names we will have.  So, we'll always add them.

  MooseEnum order = getParam<MooseEnum>("order");
  std::string family = "LAGRANGE";

  if (_quadrature)
  {
    order = "CONSTANT";
    family = "MONOMIAL";
  }

  _problem->addAuxVariable(_penetration_var_name,
                           FEType(order, Utility::string_to_enum<FEFamily>(family)));

  _problem->addAuxVariable(_gap_value_name,
                           FEType(order, Utility::string_to_enum<FEFamily>(family)));
}

void
ThermalContactAction::addBCs()
{
  const std::string object_name = getParam<std::string>("type");
  InputParameters params = _factory.getValidParams(object_name);
  params.applyParameters(parameters());

  if (_quadrature)
  {
    params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("master");
    params.set<bool>("use_displaced_mesh") = true;
  }
  else
  {
    params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
    params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
  }

  params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("slave")};

  _problem->addBoundaryCondition(object_name, "gap_bc_" + name(), params);

  if (_quadrature)
  {
    // Swap master and slave for this one
    params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("master")};
    params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("slave");

    _problem->addBoundaryCondition(object_name, "gap_bc_master_" + name(), params);
  }
}

void
ThermalContactAction::addDiracKernels()
{
  if (_quadrature)
    return;

  const std::string object_name = "GapHeatPointSourceMaster";
  InputParameters params = _factory.getValidParams(object_name);
  params.applySpecificParameters(parameters(),
                                 {"tangential_tolerance",
                                  "normal_smoothing_distance",
                                  "normal_smoothing_method",
                                  "order",
                                  "slave",
                                  "variable"});
  params.set<BoundaryName>("boundary") = getParam<BoundaryName>("master");

  _problem->addDiracKernel(object_name, object_name + "_" + name(), params);
}

void
ThermalContactAction::addMaterials()
{
  if (getParam<std::string>("type") != "GapHeatTransfer")
    return;

  const std::string object_type = "GapConductance";

  InputParameters params = _factory.getValidParams(object_type);
  params.applyParameters(parameters(), {"variable"});

  params.set<std::vector<VariableName>>("variable") = {getParam<NonlinearVariableName>("variable")};
  params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("slave")};

  if (_quadrature)
  {
    params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("master");
  }
  else
  {
    params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
    params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
  }

  _problem->addMaterial(object_type, name() + "_" + "gap_value", params);

  if (_quadrature)
  {
    params.set<BoundaryName>("paired_boundary") = getParam<BoundaryName>("slave");
    params.set<std::vector<BoundaryName>>("boundary") = {getParam<BoundaryName>("master")};

    _problem->addMaterial(object_type, name() + "_" + "gap_value_master", params);
  }
}

void
ThermalContactAction::addSlaveFluxVector()
{
  _problem->getNonlinearSystemBase().addVector("slave_flux", false, GHOSTED);
  _problem->getNonlinearSystemBase().zeroVectorForResidual("slave_flux");

  // It is risky to apply this optimization to contact problems
  // since the problem configuration may be changed during Jacobian
  // evaluation. We therefore turn it off for all contact problems so that
  // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3 or older.
  if (!_problem->isSNESMFReuseBaseSetbyUser())
    _problem->setSNESMFReuseBase(false, false);
}
<|endoftext|>


<commit_before>MatrixXi m = MatrixXi::Random(3,4);
cout << "Here is the matrix m:" << endl << m << endl;
cout << "Here is the reverse of m:" << endl << m.reverse() << endl;
cout << "Here is the coefficient (1,0) in the reverse of m:" << endl
     << m.reverse()(1,0) << endl;
cout << "Let us overwrite this coefficient with the value 4." << endl;
//m.reverse()(1,0) = 4;
cout << "Now the matrix m is:" << endl << m << endl;
<commit_msg>I doubt this change was intented to be committed<commit_after>MatrixXi m = MatrixXi::Random(3,4);
cout << "Here is the matrix m:" << endl << m << endl;
cout << "Here is the reverse of m:" << endl << m.reverse() << endl;
cout << "Here is the coefficient (1,0) in the reverse of m:" << endl
     << m.reverse()(1,0) << endl;
cout << "Let us overwrite this coefficient with the value 4." << endl;
m.reverse()(1,0) = 4;
cout << "Now the matrix m is:" << endl << m << endl;
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: wakeupevent.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: kz $ $Date: 2006-12-13 15:23:54 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_slideshow.hxx"

// must be first
#include <canvas/debug.hxx>
#include <canvas/verbosetrace.hxx>

#include <wakeupevent.hxx>

namespace slideshow
{
    namespace internal
    {
        WakeupEvent::WakeupEvent(
            boost::shared_ptr<canvas::tools::ElapsedTime> const & pTimeBase,
            ActivitiesQueue& rActivityQueue ) :
            maTimer(pTimeBase),
            mnNextTime(0.0),
            mpActivity(),
            mrActivityQueue( rActivityQueue )
        {
        }

        void WakeupEvent::dispose()
        {
            mpActivity.reset();
        }

        bool WakeupEvent::fire()
        {
            if( !mpActivity )
                return false;

            return mrActivityQueue.addActivity( mpActivity );
        }

        bool WakeupEvent::isCharged() const
        {
            // this event won't expire, we fire everytime we're
            // re-inserted into the event queue.
            return true;
        }

        double WakeupEvent::getActivationTime( double nCurrentTime ) const
        {
            const double nElapsedTime( maTimer.getElapsedTime() );

            return ::std::max( nCurrentTime,
                               nCurrentTime - nElapsedTime + mnNextTime );
        }

        void WakeupEvent::start()
        {
            // start timer
            maTimer.reset();
        }

        void WakeupEvent::setNextTimeout( double rNextTime )
        {
            mnNextTime = rNextTime;
        }

        void WakeupEvent::setActivity( const ActivitySharedPtr& rActivity )
        {
            mpActivity = rActivity;
        }
    }
}
<commit_msg>INTEGRATION: CWS changefileheader (1.7.74); FILE MERGED 2008/03/31 14:00:15 rt 1.7.74.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: wakeupevent.cxx,v $
 * $Revision: 1.8 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_slideshow.hxx"

// must be first
#include <canvas/debug.hxx>
#include <canvas/verbosetrace.hxx>

#include <wakeupevent.hxx>

namespace slideshow
{
    namespace internal
    {
        WakeupEvent::WakeupEvent(
            boost::shared_ptr<canvas::tools::ElapsedTime> const & pTimeBase,
            ActivitiesQueue& rActivityQueue ) :
            maTimer(pTimeBase),
            mnNextTime(0.0),
            mpActivity(),
            mrActivityQueue( rActivityQueue )
        {
        }

        void WakeupEvent::dispose()
        {
            mpActivity.reset();
        }

        bool WakeupEvent::fire()
        {
            if( !mpActivity )
                return false;

            return mrActivityQueue.addActivity( mpActivity );
        }

        bool WakeupEvent::isCharged() const
        {
            // this event won't expire, we fire everytime we're
            // re-inserted into the event queue.
            return true;
        }

        double WakeupEvent::getActivationTime( double nCurrentTime ) const
        {
            const double nElapsedTime( maTimer.getElapsedTime() );

            return ::std::max( nCurrentTime,
                               nCurrentTime - nElapsedTime + mnNextTime );
        }

        void WakeupEvent::start()
        {
            // start timer
            maTimer.reset();
        }

        void WakeupEvent::setNextTimeout( double rNextTime )
        {
            mnNextTime = rNextTime;
        }

        void WakeupEvent::setActivity( const ActivitySharedPtr& rActivity )
        {
            mpActivity = rActivity;
        }
    }
}
<|endoftext|>