http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9e6d233f/mgmt/stats/StatType.cc ---------------------------------------------------------------------- diff --git a/mgmt/stats/StatType.cc b/mgmt/stats/StatType.cc deleted file mode 100644 index 1c51b95..0000000 --- a/mgmt/stats/StatType.cc +++ /dev/null @@ -1,1199 +0,0 @@ -/** @file - - A brief file description - - @section license License - - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -/***************************************/ -/**************************************************************************** - * - * StatType.cc - Functions for computing node and cluster stat - * aggregation - * - * - ****************************************************************************/ - -#include "ink_config.h" -#include "StatType.h" -#include "MgmtUtils.h" -#include "ink_hrtime.h" -#include "WebOverview.h" - -bool StatError = false; // global error flag -bool StatDebug = false; // global debug flag - -/** - * StatExprToken() - * --------------- - */ -StatExprToken::StatExprToken() - : m_arith_symbol('\0'), - m_token_name(NULL), - m_token_type(RECD_NULL), - m_sum_var(false), m_node_var(true) -{ - RecDataClear(RECD_NULL, &m_token_value); - RecDataClear(RECD_NULL, &m_token_value_max); - RecDataClear(RECD_NULL, &m_token_value_min); - memset(&m_token_value_delta, 0, sizeof(m_token_value_delta)); -} - - -/** - * StatExprToken::copy() - * --------------------- - */ -void -StatExprToken::copy(const StatExprToken & source) -{ - m_arith_symbol = source.m_arith_symbol; - - if (source.m_token_name != NULL) { - m_token_name = ats_strdup(source.m_token_name); - } - - m_token_type = source.m_token_type; - m_token_value = source.m_token_value; - m_token_value_min = source.m_token_value_min; - m_token_value_max = source.m_token_value_max; - - if (source.m_token_value_delta) { - m_token_value_delta = new StatDataSamples(); - m_token_value_delta->previous_time = source.m_token_value_delta->previous_time; - m_token_value_delta->current_time = source.m_token_value_delta->current_time; - m_token_value_delta->previous_value = source.m_token_value_delta->previous_value; - m_token_value_delta->current_value = source.m_token_value_delta->current_value; - } - - m_node_var = source.m_node_var; - m_sum_var = source.m_sum_var; -} - - -/** - * StatExprToken::assignTokenName() - * -------------------------------- - * Assign the token name. If the token is a predefined constant, - * assign the value as well. Also, assign the token type as well. - */ -void -StatExprToken::assignTokenName(const char *name) -{ - - if (isdigit(name[0])) { - // numerical constant - m_token_name = ats_strdup("CONSTANT"); - m_token_type = RECD_CONST; - } else { - m_token_name = ats_strdup(name); - assignTokenType(); - } - - switch (m_token_type) { - case RECD_INT: - case RECD_COUNTER: - case RECD_FLOAT: - break; - case RECD_CONST: - // assign pre-defined constant in here - // constant will be stored as RecFloat type. - if (!strcmp(m_token_name, "CONSTANT")) { - m_token_value.rec_float = (RecFloat) atof(name); - } else if (!strcmp(m_token_name, "$BYTES_TO_MB_SCALE")) { - m_token_value.rec_float = (RecFloat) BYTES_TO_MB_SCALE; - } else if (!strcmp(m_token_name, "$MBIT_TO_KBIT_SCALE")) { - m_token_value.rec_float = (RecFloat) MBIT_TO_KBIT_SCALE; - } else if (!strcmp(m_token_name, "$SECOND_TO_MILLISECOND_SCALE")) { - m_token_value.rec_float = (RecFloat) SECOND_TO_MILLISECOND_SCALE; - } else if (!strcmp(m_token_name, "$PCT_TO_INTPCT_SCALE")) { - m_token_value.rec_float = (RecFloat) PCT_TO_INTPCT_SCALE; - } else if (!strcmp(m_token_name, "$HRTIME_SECOND")) { - m_token_value.rec_float = (RecFloat) HRTIME_SECOND; - } else if (!strcmp(m_token_name, "$BYTES_TO_MBIT_SCALE")) { - m_token_value.rec_float = (RecFloat) BYTES_TO_MBIT_SCALE; - } else { - mgmt_log(stderr, "[StatPro] ERROR: Undefined constant: %s\n", m_token_name); - StatError = true; - } - case RECD_FX: - default: - break; - } -} - - -/** - * assignTokenType() - * ----------------- - * Assign the proper token type based on the token name. - * Do some token type conversion if necessary. Return true - * if the token type is recognizable; false otherwise. - */ -bool StatExprToken::assignTokenType() -{ - ink_assert(m_token_name != NULL); - m_token_type = varType(m_token_name); - - if (m_token_name[0] == '$') { - m_token_type = RECD_CONST; - } else if (m_token_name[0] == '_') { - m_token_type = RECD_FX; - } - - if (m_token_value_delta) { - m_token_value_delta->data_type = m_token_type; - } - - // I'm guessing here that we want to check if we're still RECD_NULL, - // it used to be INVALID, which is not in the m_token_type's enum. /leif - return (m_token_type != RECD_NULL); -} - - -void -StatExprToken::clean() -{ - ats_free(m_token_name); - delete m_token_value_delta; -} - - -/** - * FOR DEBUGGING ONLY - * Print the token according to its type in a human-readable format. :) - */ -void -StatExprToken::print(const char *prefix) -{ - if (m_token_name != NULL) { - printf("%s\t%s\n", prefix, m_token_name); - } else { - printf("%s\t%c\n", prefix, m_arith_symbol); - } -} - - -/** - * StatExprToken::precedence() - * --------------------------- - * Return the binary operator precedence. The higher returning value, - * the higher the precedence value. - */ -short -StatExprToken::precedence() -{ - switch (m_arith_symbol) { - case '(': - return 4; - case '^': // fall through - case '!': - return 3; - case '*': // fall through - case '/': - return 2; - case '+': // fall through - case '-': - return 1; - default: - return -1; - } -} - - -/** - * StatExprToken::statVarSet() - * --------------------------- - * This method is responsible for ensuring the assigning value - * fall within the min. and max. bound. If it's smaller than min. - * or larger than max, then the error value is assigned. If no - * error value is assigned, either min. or max. is assigned. - */ -bool StatExprToken::statVarSet(RecDataT type, RecData value) -{ - RecData converted_value; - - if (StatError) { - /* fix this after librecords is done - mgmt_log(stderr, - "[StatPro] ERROR in a statistics aggregation operations\n"); - */ - RecData err_value; - RecDataClear(m_token_type, &err_value); - return varSetData(m_token_type, m_token_name, err_value); - } - - /* - * do conversion if necessary. - */ - if (m_token_type != type) { - switch (m_token_type) { - case RECD_INT: - case RECD_COUNTER: - if (type == RECD_NULL) - converted_value = value; - else if (type == RECD_INT || type == RECD_COUNTER || type == RECD_FX) - converted_value.rec_int = value.rec_int; - else if (type == RECD_FLOAT || type == RECD_CONST) - converted_value.rec_int = (RecInt)value.rec_float; - else - Fatal("%s, invalid value type:%d\n", m_token_name, type); - break; - case RECD_FLOAT: - if (type == RECD_NULL) - converted_value = value; - else if (type == RECD_INT || type == RECD_COUNTER || type == RECD_FX) - converted_value.rec_float = (RecFloat)value.rec_int; - else if (type == RECD_FLOAT || type == RECD_CONST) - converted_value.rec_float = value.rec_float; - else - Fatal("%s, invalid value type:%d\n", m_token_name, type); - break; - default: - Fatal("%s, unsupported token type:%d\n", m_token_name, m_token_type); - } - } else { - converted_value = value; - } - - if (RecDataCmp(m_token_type, converted_value, m_token_value_min) < 0) { - value = m_token_value_min; - } - else if (RecDataCmp(m_token_type, converted_value, m_token_value_max) > 0) { - value = m_token_value_max; - } - - return varSetData(m_token_type, m_token_name, converted_value); -} - - -/*********************************************************************** - StatExprList - **********************************************************************/ - -/** - * StatExprList::StatExprList() - * ---------------------------- - */ -StatExprList::StatExprList() - : m_size(0) -{ -} - - -/** - * StatExprList::clean() - * --------------------- - */ -void -StatExprList::clean() -{ - StatExprToken *temp = NULL; - - while ((temp = m_tokenList.dequeue())) { - delete(temp); - m_size -= 1; - } - ink_assert(m_size == 0); -} - - -void -StatExprList::enqueue(StatExprToken * entry) -{ - ink_assert(entry); - m_tokenList.enqueue(entry); - m_size += 1; -} - - -void -StatExprList::push(StatExprToken * entry) -{ - ink_assert(entry); - m_tokenList.push(entry); - m_size += 1; -} - - -StatExprToken * -StatExprList::dequeue() -{ - if (m_size == 0) { - return NULL; - } - m_size -= 1; - return (StatExprToken *) m_tokenList.dequeue(); -} - - -StatExprToken * -StatExprList::pop() -{ - if (m_size == 0) { - return NULL; - } - m_size -= 1; - return m_tokenList.pop(); -} - - -StatExprToken * -StatExprList::top() -{ - if (m_size == 0) { - return NULL; - } - return m_tokenList.head; -} - - -StatExprToken * -StatExprList::first() -{ - if (m_size == 0) { - return NULL; - } - return m_tokenList.head; -} - - -StatExprToken * -StatExprList::next(StatExprToken * current) -{ - if (!current) { - return NULL; - } - return (current->link).next; -} - - -/** - * StatExprList::print() - * --------------------- - * Print the token in the expression in a human-readable format. :) - */ -void -StatExprList::print(const char *prefix) -{ - for (StatExprToken * token = first(); token; token = next(token)) { - token->print(prefix); - } -} - - -/** - * StatExprToken::count() - * ---------------------- - * Counts the number of token in the expression list and return it. - */ -unsigned -StatExprList::count() -{ - return m_size; -} - - -/*********************************************************************** - StatObject - **********************************************************************/ - - -/** - * StatObject::StatObject() - * ------------------------ - */ - -StatObject::StatObject() - : m_id(1), - m_debug(false), - m_expr_string(NULL), - m_node_dest(NULL), - m_cluster_dest(NULL), - m_expression(NULL), - m_postfix(NULL), - m_last_update(-1), - m_current_time(-1), m_update_interval(-1), - m_stats_max(FLT_MAX), m_stats_min(FLT_MIN), - m_has_max(false), m_has_min(false), m_has_delta(false) -{ -} - - -StatObject::StatObject(unsigned identifier) - : m_id(identifier), - m_debug(false), - m_expr_string(NULL), - m_node_dest(NULL), - m_cluster_dest(NULL), - m_expression(NULL), - m_postfix(NULL), - m_last_update(-1), - m_current_time(-1), m_update_interval(-1), - m_stats_max(FLT_MAX), m_stats_min(FLT_MIN), - m_has_max(false), m_has_min(false), m_has_delta(false) -{ -} - - -/** - * StatObject::clean() - * ------------------- - */ -void -StatObject::clean() -{ - ats_free(m_expr_string); - delete m_node_dest; - delete m_cluster_dest; - delete m_postfix; -} - - -/** - * StatObject::assignDst() - * ----------------------- - */ -void -StatObject::assignDst(const char *str, bool m_node_var, bool m_sum_var) -{ - if (StatDebug) { - Debug(MODULE_INIT, "DESTINTATION: %s\n", str); - } - - StatExprToken *statToken = new StatExprToken(); - - statToken->assignTokenName(str); - statToken->m_node_var = m_node_var; - statToken->m_sum_var = m_sum_var; - - // The type of dst token should be always not NULL - if (statToken->m_token_type == RECD_NULL) { - Fatal("token:%s, invalid token type!", statToken->m_token_name); - } - - // Set max/min value - if (m_has_max) - RecDataSetFromFloat(statToken->m_token_type, &statToken->m_token_value_max, - m_stats_max); - else - RecDataSetMax(statToken->m_token_type, &statToken->m_token_value_max); - - if (m_has_min) - RecDataSetFromFloat(statToken->m_token_type, &statToken->m_token_value_min, - m_stats_min); - else - RecDataSetMin(statToken->m_token_type, &statToken->m_token_value_min); - - if (m_node_var) { - ink_assert(m_node_dest == NULL); - m_node_dest = statToken; - } else { - ink_assert(m_cluster_dest == NULL); - m_cluster_dest = statToken; - } -} - - -/** - * StatObject::assignExpr() - * ------------------------ - */ -void -StatObject::assignExpr(char *str) -{ - StatExprToken *statToken = NULL; - - if (StatDebug) { - Debug(MODULE_INIT, "EXPRESSION: %s\n", str); - } - ink_assert(m_expr_string == NULL); - // We take ownership here - m_expr_string = str; - - Tokenizer exprTok(" "); - exprTok.Initialize(str); - tok_iter_state exprTok_state; - const char *token = exprTok.iterFirst(&exprTok_state); - - ink_assert(m_expression == NULL); - m_expression = new StatExprList(); - - while (token) { - - statToken = new StatExprToken(); - - if (isOperator(token[0])) { - - statToken->m_arith_symbol = token[0]; - ink_assert(statToken->m_token_name == NULL); - - if (StatDebug) { - Debug(MODULE_INIT, "\toperator: ->%c<-\n", statToken->m_arith_symbol); - } - - } else { - - ink_assert(statToken->m_arith_symbol == '\0'); - - // delta - if (token[0] == '#') { - - token += 1; // skip '#' - statToken->m_token_value_delta = new StatDataSamples(); - statToken->m_token_value_delta->previous_time = (ink_hrtime) 0; - statToken->m_token_value_delta->current_time = (ink_hrtime) 0; - statToken->m_token_value_delta->data_type = RECD_NULL; - RecDataClear(RECD_NULL, &statToken->m_token_value_delta->previous_value); - RecDataClear(RECD_NULL, &statToken->m_token_value_delta->current_value); - - } - - statToken->assignTokenName(token); - - if (StatDebug) { - Debug(MODULE_INIT, "\toperand: ->%s<-\n", token); - } - - } - - token = exprTok.iterNext(&exprTok_state); - m_expression->enqueue(statToken); - - } - - infix2postfix(); - -} - - -/** - * StatObject::infix2postfix() - * --------------------------- - * Takes the infix "expression" and convert it to a postfix for future - * evaluation. - * - * SIDE EFFECT: consume all token in "expression" - */ -void -StatObject::infix2postfix() -{ - StatExprList stack; - StatExprToken *tempToken = NULL; - StatExprToken *curToken = NULL; - m_postfix = new StatExprList(); - - while (m_expression->top()) { - curToken = m_expression->dequeue(); - - if (!isOperator(curToken->m_arith_symbol)) { - //printf("I2P~: enqueue %s\n", curToken->m_token_name); - m_postfix->enqueue(curToken); - - } else { - ink_assert(curToken->m_arith_symbol != '\0'); - - if (curToken->m_arith_symbol == '(') { - stack.push(curToken); - } else if (curToken->m_arith_symbol == ')') { - tempToken = (StatExprToken *) stack.pop(); - - while (tempToken->m_arith_symbol != '(') { - //printf("I2P@: enqueue %c\n", tempToken->m_arith_symbol); - m_postfix->enqueue(tempToken); - tempToken = (StatExprToken *) stack.pop(); - } - - // Free up memory for ')' - delete(curToken); - delete(tempToken); - - } else { - if (stack.count() == 0) { - stack.push(curToken); - } else { - tempToken = (StatExprToken *) stack.top(); - - while ((tempToken->m_arith_symbol != '(') && (tempToken->precedence() >= curToken->precedence())) { - tempToken = (StatExprToken *) stack.pop(); // skip the ( - //printf("I2P$: enqueue %c\n", tempToken->m_arith_symbol); - m_postfix->enqueue(tempToken); - if (stack.count() == 0) { - break; - } - tempToken = (StatExprToken *) stack.top(); - } // while - - stack.push(curToken); - } - } - } - } - - while (stack.count() > 0) { - tempToken = (StatExprToken *) stack.pop(); - //printf("I2P?: enqueue %c\n", tempToken->m_arith_symbol); - m_postfix->enqueue(tempToken); - } - - // dump infix expression - delete(m_expression); - m_expression = NULL; -} - - -/** - * StatObject::NodeStatEval() - * -------------------------- - * - * - */ -RecData StatObject::NodeStatEval(RecDataT *result_type, bool cluster) -{ - StatExprList stack; - StatExprToken *left = NULL; - StatExprToken *right = NULL; - StatExprToken *result = NULL; - StatExprToken *curToken = NULL; - RecData tempValue; - RecDataClear(RECD_NULL, &tempValue); - - *result_type = RECD_NULL; - - /* Express checkout lane -- Stat. object with on 1 source variable */ - if (m_postfix->count() == 1) { - StatExprToken * src = m_postfix->top(); - - // in librecords, not all statistics are register at initialization - // must assign proper type if it is undefined. - if (src->m_token_type == RECD_NULL) { - src->assignTokenType(); - } - - *result_type = src->m_token_type; - if (src->m_token_type == RECD_CONST) { - tempValue = src->m_token_value; - } else if (src->m_token_value_delta) { - tempValue = src->m_token_value_delta->diff_value(src->m_token_name); - } else if (!cluster) { - if (!varDataFromName(src->m_token_type, src->m_token_name, &tempValue)) { - RecDataClear(src->m_token_type, &tempValue); - } - } else { - if (!overviewGenerator->varClusterDataFromName(src->m_token_type, - src->m_token_name, - &tempValue)) { - RecDataClear(src->m_token_type, &tempValue); - } - } - } else { - - /* standard postfix evaluation */ - for (StatExprToken * token = m_postfix->first(); token; token = m_postfix->next(token)) { - /* carbon-copy the token. */ - curToken = new StatExprToken(); - curToken->copy(*token); - - if (!isOperator(curToken->m_arith_symbol)) { - stack.push(curToken); - } else { - ink_assert(isOperator(curToken->m_arith_symbol)); - right = stack.pop(); - left = stack.pop(); - - if (left->m_token_type == RECD_NULL) { - left->assignTokenType(); - } - if (right->m_token_type == RECD_NULL) { - right->assignTokenType(); - } - - result = StatBinaryEval(left, curToken->m_arith_symbol, right, cluster); - - stack.push(result); - delete(curToken); - delete(left); - delete(right); - } - } - - /* should only be 1 value left on stack -- the resulting value */ - if (stack.count() > 1) { - stack.print("\t"); - ink_assert(false); - } - - *result_type = stack.top()->m_token_type; - tempValue = stack.top()->m_token_value; - } - - return tempValue; - -} - - -/** - * StatObject::ClusterStatEval() - * ----------------------------- - * - * - */ -RecData StatObject::ClusterStatEval(RecDataT *result_type) -{ - /* Sanity check */ - ink_assert(m_cluster_dest && !m_cluster_dest->m_node_var); - - // what is this? - if ((m_node_dest == NULL) || (m_cluster_dest->m_sum_var == false)) { - return NodeStatEval(result_type, true); - } else { - RecData tempValue; - - if (!overviewGenerator->varClusterDataFromName(m_node_dest->m_token_type, - m_node_dest->m_token_name, - &tempValue)) { - *result_type = RECD_NULL; - RecDataClear(*result_type, &tempValue); - } - - return (tempValue); - } -} - - -/** - * StatObject::setTokenValue() - * --------------------------- - * The logic of the following code segment is the following. - * The objective is to extract the appropriate right->m_token_value. - * If 'right' is an intermediate value, nothing to do. - * If m_token_type is RECD_CONST, nothing to do. - * If m_token_type is RECD_FX, right->m_token_value is the diff. in time. - * If m_token_type is either RECD_INT or RECD_FLOAT, it can either - * by a cluster variable or a node variable. - * If it is a cluster variable, just use varClusterFloatFromName - * to set right->m_token_value. - * If it is a node variable, then it can either be a variable - * with delta. To determine whether it has a delta, simply search - * the m_token_name in the delta list. If found then it has delta. - * If it has delta then use the delta's diff. in value, - * otherwise simply set right->m_token_value with varFloatFromName. - */ -void -StatObject::setTokenValue(StatExprToken * token, bool cluster) -{ - if (token->m_token_name) { - // it is NOT an intermediate value - - switch (token->m_token_type) { - case RECD_CONST: - break; - - case RECD_FX: - // only support time function - // use rec_int to store time value - token->m_token_value.rec_int = (m_current_time - m_last_update); - break; - - case RECD_INT: // fallthought - case RECD_COUNTER: - case RECD_FLOAT: - if (cluster) { - if (!overviewGenerator->varClusterDataFromName(token->m_token_type, - token->m_token_name, - &(token->m_token_value))) - { - RecDataClear(token->m_token_type, &token->m_token_value); - } - } else { - if (token->m_token_value_delta) { - token->m_token_value = - token->m_token_value_delta->diff_value(token->m_token_name); - } else { - if (!varDataFromName(token->m_token_type, token->m_token_name, - &(token->m_token_value))) { - RecDataClear(token->m_token_type, &token->m_token_value); - } - } // delta? - } // cluster? - break; - - default: - if (StatDebug) { - Debug(MODULE, "Unrecognized token \"%s\" of type %d.\n", - token->m_token_name, token->m_token_type); - } - } // switch - } // m_token_name? -} - - -/** - * StatObject::StatBinaryEval() - * ------------------------ - * Take the left token, the right token, an binary operation and perform an - * arithmatic operations on them. This function is responsible for getting the - * correct value from: - * - (1) node variable - * - (2) node variable with a delta structure - * - (3) cluster variable - * - (4) an immediate value - */ -StatExprToken *StatObject::StatBinaryEval(StatExprToken * left, char op, - StatExprToken * right, bool cluster) -{ - RecData l, r; - StatExprToken *result = new StatExprToken(); - result->m_token_type = RECD_INT; - - if (left->m_token_type == RECD_NULL - && right->m_token_type == RECD_NULL) { - return result; - } - - if (left->m_token_type != RECD_NULL) { - setTokenValue(left, cluster); - result->m_token_type = left->m_token_type; - } - - if (right->m_token_type != RECD_NULL) { - setTokenValue(right, cluster); - switch (result->m_token_type) { - case RECD_NULL: - result->m_token_type = right->m_token_type; - break; - case RECD_FX: - case RECD_INT: - case RECD_COUNTER: - /* - * When types of left and right are different, select RECD_FLOAT - * as result type. It's may lead to loss of precision when do - * conversion, be careful! - */ - if (right->m_token_type == RECD_FLOAT - || right->m_token_type == RECD_CONST) { - result->m_token_type = right->m_token_type; - } - break; - case RECD_CONST: - case RECD_FLOAT: - break; - default: - Fatal("Unexpected RecData Type:%d", result->m_token_type); - break; - } - } - - /* - * We should make the operands with the same type before calculating. - */ - RecDataClear(RECD_NULL, &l); - RecDataClear(RECD_NULL, &r); - - if (left->m_token_type == right->m_token_type ) { - l = left->m_token_value; - r = right->m_token_value; - } else if (result->m_token_type != left->m_token_type) { - if (left->m_token_type != RECD_NULL) { - ink_assert(result->m_token_type == RECD_FLOAT - || result->m_token_type == RECD_CONST); - - l.rec_float = (RecFloat)left->m_token_value.rec_int; - } - r = right->m_token_value; - ink_assert(result->m_token_type == right->m_token_type); - } else { - l = left->m_token_value; - if (right->m_token_type != RECD_NULL) { - ink_assert(result->m_token_type == RECD_FLOAT - || result->m_token_type == RECD_CONST); - - r.rec_float = (RecFloat)right->m_token_value.rec_int; - } - ink_assert(result->m_token_type == left->m_token_type); - } - - /* - * Start to calculate - */ - switch (op) { - case '+': - result->m_token_value = RecDataAdd(result->m_token_type, l, r); - break; - - case '-': - result->m_token_value = RecDataSub(result->m_token_type, l, r); - break; - - case '*': - result->m_token_value = RecDataMul(result->m_token_type, l, r); - break; - - case '/': - RecData recTmp; - RecDataClear(RECD_NULL, &recTmp); - - /* - * Force the type of result to be RecFloat on div operation - */ - if (result->m_token_type != RECD_FLOAT && result->m_token_type != RECD_CONST) { - RecFloat t; - - result->m_token_type = RECD_FLOAT; - - t = (RecFloat)l.rec_int; - l.rec_float = t; - - t = (RecFloat)r.rec_int; - r.rec_float = t; - } - - if (RecDataCmp(result->m_token_type, r, recTmp)) { - result->m_token_value = RecDataDiv(result->m_token_type, l, r); - } - break; - - default: - // should never reach here - StatError = true; - } - - return (result); -} - - -/*********************************************************************** - StatObjectList - **********************************************************************/ - -StatObjectList::StatObjectList() - : m_size(0) -{ -} - - -void -StatObjectList::clean() -{ - StatObject *temp = NULL; - - while ((temp = m_statList.dequeue())) { - m_size -= 1; - delete(temp); - } - - ink_assert(m_size == 0); -} - - -void -StatObjectList::enqueue(StatObject * object) -{ - for (StatExprToken * token = object->m_postfix->first(); token; token = object->m_postfix->next(token)) { - if (token->m_token_value_delta) { - object->m_has_delta = true; - break; - } - } - - m_statList.enqueue(object); - m_size += 1; -} - - -StatObject * -StatObjectList::first() -{ - return m_statList.head; -} - - -StatObject * -StatObjectList::next(StatObject * current) -{ - return (current->link).next; -} - - -/** - * StatObjectList::Eval() - * ---------------------- - * The statisitic processor entry point to perform the calculation. - */ -short -StatObjectList::Eval() -{ - RecData tempValue; - RecData result; - RecDataT result_type; - ink_hrtime threshold = 0; - ink_hrtime delta = 0; - short count = 0; - - RecDataClear(RECD_NULL, &tempValue); - RecDataClear(RECD_NULL, &result); - - for (StatObject * object = first(); object; object = next(object)) { - StatError = false; - StatDebug = object->m_debug; - - if (StatDebug) { - Debug(MODULE, "\n##### %d #####\n", object->m_id); - } - - if (object->m_update_interval <= 0) { - // non-time statistics - object->m_current_time = ink_get_hrtime_internal(); - - if (object->m_node_dest) { - result = object->NodeStatEval(&result_type, false); - object->m_node_dest->statVarSet(result_type, result); - } - - if (object->m_cluster_dest) { - result = object->ClusterStatEval(&result_type); - object->m_cluster_dest->statVarSet(result_type, result); - } - - object->m_last_update = object->m_current_time; - } else { - // timed statisitics - object->m_current_time = ink_get_hrtime_internal(); - - threshold = object->m_update_interval * HRTIME_SECOND; - delta = object->m_current_time - object->m_last_update; - - if (StatDebug) { - Debug(MODULE, "\tUPDATE:%" PRId64 " THRESHOLD:%" PRId64 ", DELTA:%" PRId64 "\n", object->m_update_interval, threshold, delta); - } - - /* Should we do the calculation? */ - if ((delta > threshold) || /* sufficient elapsed time? */ - (object->m_last_update == -1) || /* first time? */ - (object->m_last_update > object->m_current_time)) { /*wrapped */ - - if (StatDebug) { - if (delta > threshold) { - Debug(MODULE, "\t\tdelta > threshold IS TRUE!\n"); - } - if (object->m_last_update == -1) { - Debug(MODULE, "\t\tm_last_update = -1 IS TRUE!\n"); - } - if (object->m_last_update > object->m_current_time) { - Debug(MODULE, "\t\tm_last_update > m_current_time IS TRUE\n"); - } - } - - if (!object->m_has_delta) { - - if (StatDebug) { - Debug(MODULE, "\tEVAL: Simple time-condition.\n"); - } - - if (object->m_node_dest) { - result = object->NodeStatEval(&result_type, false); - object->m_node_dest->statVarSet(result_type, result); - } - - if (object->m_cluster_dest) { - result = object->ClusterStatEval(&result_type); - object->m_cluster_dest->statVarSet(result_type, result); - } - - object->m_last_update = object->m_current_time; - } else { - /* has delta */ - if (StatDebug) { - Debug(MODULE, "\tEVAL: Complicated time-condition.\n"); - } - // scroll old values - for (StatExprToken * token = object->m_postfix->first(); token; token = object->m_expression->next(token)) { - - // in librecords, not all statistics are register at initialization - // must assign proper type if it is undefined. - if (!isOperator(token->m_arith_symbol) && token->m_token_type == RECD_NULL) { - token->assignTokenType(); - } - - if (token->m_token_value_delta) { - if (!varDataFromName(token->m_token_type, token->m_token_name, - &tempValue)) { - RecDataClear(RECD_NULL, &tempValue); - } - - token->m_token_value_delta->previous_time = token->m_token_value_delta->current_time; - token->m_token_value_delta->previous_value = token->m_token_value_delta->current_value; - token->m_token_value_delta->current_time = object->m_current_time; - token->m_token_value_delta->current_value = tempValue; - } - } - - if (delta > threshold) { - if (object->m_node_dest) { - result = object->NodeStatEval(&result_type, false); - object->m_node_dest->statVarSet(result_type, result); - } - - if (object->m_cluster_dest) { - result = object->ClusterStatEval(&result_type); - object->m_cluster_dest->statVarSet(result_type, result); - } - - object->m_last_update = object->m_current_time; - } else { - if (StatDebug) { - Debug(MODULE, "\tEVAL: Timer not expired, do nothing\n"); - } - } - } /* delta? */ - } else { - if (StatDebug) { - Debug(MODULE, "\tEVAL: Timer not expired, nor 1st time, nor wrapped, SORRY!\n"); - } - } /* timed event */ - } - count += 1; - } /* for */ - - return count; -} /* Eval() */ - - -/** - * StatObjectList::print() - * -------------------------- - * Print the list of of statistics object in a human-readable format. :) - */ -void -StatObjectList::print(const char *prefix) -{ - for (StatObject * object = first(); object; object = next(object)) { - if (StatDebug) { - Debug(MODULE, "\n%sSTAT OBJECT#: %d\n", prefix, object->m_id); - } - - if (object->m_expression) { - object->m_expression->print("\t"); - } - - if (object->m_postfix) { - object->m_postfix->print("\t"); - } - } -}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9e6d233f/mgmt/stats/StatType.h ---------------------------------------------------------------------- diff --git a/mgmt/stats/StatType.h b/mgmt/stats/StatType.h deleted file mode 100644 index 673e1e7..0000000 --- a/mgmt/stats/StatType.h +++ /dev/null @@ -1,231 +0,0 @@ -/** @file - - A brief file description - - @section license License - - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -/***************************************/ -/**************************************************************************** - * - * StatType.h - Functions for computing node and cluster stat - * aggregation - * - * - ****************************************************************************/ - -#ifndef _STATTYPE_H_ -#define _STATTYPE_H_ - -#include "StatXML.h" -#include "Main.h" // Debug() -#include "WebMgmtUtils.h" - -#define BYTES_TO_MBIT_SCALE (8/1000000.0) - -/* Structs used in Average Statistics calculations */ -struct StatDataSamples -{ - ink_hrtime previous_time; - ink_hrtime current_time; - RecDataT data_type; - RecData previous_value; - RecData current_value; - - RecData diff_value(const char *name) - { - RecData tmp; - - if (data_type == RECD_NULL) { - data_type = varType(name); - } - - if (data_type != RECD_NULL) - return RecDataSub(data_type, current_value, previous_value); - else { - RecDataClear(RECD_NULL, &tmp); - return tmp; - } - } - ink_hrtime diff_time() - { - return (current_time - previous_time); - } -}; - -// Urgly workaround -- no optimization in HPUX -#if defined(hpux) -#define inline -#endif - -#define MODULE "StatPro" // Statistics processor debug tag -#define MODULE_INIT "StatProInit" // Statistics processor debug tag - -/*************************************************************** - * StatExprToken - * a statistics expression token can either be a binary operator, - * name '+', '-', '*', '/', or parenthesis '(', ')' or a TS variable. - * In the former case, the arithSymbol stores the operator or - * paranthesis; otherwise arithSymbol is '/0'; - ***************************************************************/ -class StatExprToken -{ - -public: - - char m_arith_symbol; - char *m_token_name; - RecDataT m_token_type; - RecData m_token_value; - RecData m_token_value_max; - RecData m_token_value_min; - StatDataSamples *m_token_value_delta; - bool m_sum_var; - bool m_node_var; - - // Member Functions - void assignTokenName(const char *); - bool assignTokenType(); - void print(const char *); - short precedence(); - void copy(const StatExprToken &); - - LINK(StatExprToken, link); - StatExprToken(); - inline ~ StatExprToken() - { - clean(); - }; - void clean(); - - bool statVarSet(RecDataT, RecData); -}; - - -/** - * StatExprList - * simply a list of StatExprToken. - **/ -class StatExprList -{ - -public: - - StatExprList(); - inline ~ StatExprList() - { - clean(); - }; - void clean(); - - void enqueue(StatExprToken *); - void push(StatExprToken *); - StatExprToken *dequeue(); - StatExprToken *pop(); - StatExprToken *top(); - StatExprToken *first(); - StatExprToken *next(StatExprToken *); - unsigned count(); - void print(const char *); - -private: - - size_t m_size; - Queue<StatExprToken> m_tokenList; -}; - -/*************************************************************** - * StatObject - * Each entry in the statistics XML file is represented by a - * StatObject. - ***************************************************************/ -class StatObject -{ - -public: - - unsigned m_id; - bool m_debug; - char *m_expr_string; /* for debugging using only */ - StatExprToken *m_node_dest; - StatExprToken *m_cluster_dest; - StatExprList *m_expression; - StatExprList *m_postfix; - ink_hrtime m_last_update; - ink_hrtime m_current_time; - ink_hrtime m_update_interval; - RecFloat m_stats_max; - RecFloat m_stats_min; - bool m_has_max; - bool m_has_min; - bool m_has_delta; - LINK(StatObject, link); - - // Member functions - StatObject(); - StatObject(unsigned); - inline ~ StatObject() - { - clean(); - }; - void clean(); - void assignDst(const char *, bool, bool); - void assignExpr(char *); - - StatExprToken *StatBinaryEval(StatExprToken *, char, StatExprToken *, bool cluster = false); - RecData NodeStatEval(RecDataT *result_type, bool cluster); - RecData ClusterStatEval(RecDataT *result_type); - void setTokenValue(StatExprToken *, bool cluster = false); - -private: - - void infix2postfix(); -}; - - -/** - * StatObjectList - * simply a list of StatObject. - **/ -class StatObjectList -{ - -public: - - // Member functions - StatObjectList(); - inline ~ StatObjectList() - { - clean(); - }; - void clean(); - void enqueue(StatObject * object); - StatObject *first(); - StatObject *next(StatObject * current); - void print(const char *prefix = ""); - short Eval(); // return the number of statistics object processed - - size_t m_size; - -private: - - Queue<StatObject> m_statList; -}; - -#endif http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9e6d233f/mgmt/stats/StatXML.cc ---------------------------------------------------------------------- diff --git a/mgmt/stats/StatXML.cc b/mgmt/stats/StatXML.cc deleted file mode 100644 index 277b84a..0000000 --- a/mgmt/stats/StatXML.cc +++ /dev/null @@ -1,82 +0,0 @@ -/** @file - - A brief file description - - @section license License - - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#include "ink_config.h" -#include "StatXML.h" -#include <stdlib.h> -#include <ctype.h> - -// -// Extract the text between a pair of XML tag and returns the length -// of the extracted text. -// -unsigned short -XML_extractContent(const char *name, char *content, size_t result_len) -{ - - char c; - int contentIndex = 0; - - memset(content, 0, result_len); - for (unsigned short nameIndex = 0; name[nameIndex] != '<'; nameIndex += 1) { - c = name[nameIndex]; - - if (isspace(c)) { - continue; - } - - if (isOperator(c)) { - content[contentIndex++] = ' '; - content[contentIndex++] = c; - content[contentIndex++] = ' '; - } else { - content[contentIndex++] = c; - } - } - - return (strlen(content)); - -} - - -// -// Returns true if 'c'is an operator (in our definition), -// false otherwise -// -bool -isOperator(char c) -{ - - switch (c) { - case '+': - case '-': - case '*': - case '/': - case '(': - case ')': - return true; - default: - return false; - } - -} http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9e6d233f/mgmt/stats/StatXML.h ---------------------------------------------------------------------- diff --git a/mgmt/stats/StatXML.h b/mgmt/stats/StatXML.h deleted file mode 100644 index b31063b..0000000 --- a/mgmt/stats/StatXML.h +++ /dev/null @@ -1,47 +0,0 @@ -/** @file - - A brief file description - - @section license License - - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - - -#ifndef _STATXML_H_ -#define _STATXML_H_ - -#include "WebMgmtUtils.h" -#include "List.h" - -typedef enum -{ - INVALID_TAG = -1, - ROOT_TAG, - STAT_TAG, - DST_TAG, - EXPR_TAG -} StatXMLTag; - -/*************************************************************** - * General Methods - ***************************************************************/ -bool isOperator(char); -int XML_getContent(const char *, int, char *, StatXMLTag); -unsigned short XML_extractContent(const char *, char *, size_t); - -#endif http://git-wip-us.apache.org/repos/asf/trafficserver/blob/9e6d233f/mgmt/stats/spec ---------------------------------------------------------------------- diff --git a/mgmt/stats/spec b/mgmt/stats/spec deleted file mode 100644 index 97bdb90..0000000 --- a/mgmt/stats/spec +++ /dev/null @@ -1,236 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Statistics Processor -// -// Last Update: 04/11/2001 -// -//----------------------------------------------------------------------------- -// -*- coding: utf-8 -*- -// -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -//----------------------------------------------------------------------------- -// Design -//----------------------------------------------------------------------------- - -This statistics processor is a Cougar II (Tsunami) feature. -It is designed to replace the StatAggregate.cc and portion of WebOverview.cc -for scalability, maintainability, and ability to customize reasons. - -The statistics processor aggregate/calculate traffic server statistics based -on a XML-based configuration file. At the processor's initialization, the -configuration file is read and parsed. Each set of calculation is then stored -as a C++ object, called StatObject; and each StatObject is linked into a list, -called StatObjectList. - -The mgmt/traffic_manager threads will invoke the StatObjectList->Eval() to -perform the statistics aggregation and calculation within its event loop. As -Eval() is call, each StatObject in StatObjectList is evaluated. - -Recall: StatAggregate.cc aggregates/calculates/copies proxy.process.* TS -variables to proxy.node.* variables. Similarly, WebOverview.cc aggregate -proxy.node.* variables to their corresponding proxy.cluster.* variable. - -So there are two types of calculations in the statistics processor: NodeEval -and ClusterEval. As their names imply, they aggregate node-based statistics -and clsuter-based statistics, respectively. We call the different basis of -statistics aggregation as "scope". (See "Destination Attributes") - -In the cluster-based statistics, the aggregation is further divided into two -types: sum and re-calculate. Sum refers calculating the proxy.cluster.* -variable by simply summing all required proxy.node.* variables from nodes in -the cluster. Re-calculate refers to summing all proxy.nodes.* variables that -are used in the process of calculation before performing the calculation. -An analogy would be, summing all open connection in the cluster vs. the -average hit rate in the cluster. - -//----------------------------------------------------------------------------- -// Destination Attributes -//----------------------------------------------------------------------------- - - "scope" - - "node" - - "cluster" - - "operation" - - "sum" - summing the corresponding node variable across all nodes in the cluster. - - "re-calculate" - - - "define" - - "custom" - - "built-in" - -//----------------------------------------------------------------------------- -// Predefined Constants and Functions -//----------------------------------------------------------------------------- - - Predefined Constants - - . BYTES_TO_MB_SCALE (1/(1024*1024.0)) - - convert bytes to mega-bytes - - . MBIT_TO_KBIT_SCALE (1000.0) - - convert mega-bits to kilo-bits - - . SECOND_TO_MILLISECOND_SCALE (1000.0) - - convert seconds to milliseconds - - . PCT_TO_INTPCT_SCALE (100.0) - - convert ratios to percentage - - . HRTIME_SECOND - - converting milli-seconds to seconds - - . BYTES_TO_MBIT_SCALE (8/1000000.0) - - convert bytes to mega-bits - - Predefined Functions - . DIFFTIME - - the number of milliseconds since last update. Usually used in - combination of HRTIME_SECOND which computes the number of seconds - since last update. - -//----------------------------------------------------------------------------- -// Unit test plan -//----------------------------------------------------------------------------- - -The statistics processor is designed to replace StatAggregate.cc and part of -the WebOverview. The first thing to test StatProcessor is to comment the -aggregateNodeRecords() and doClusterAg() calls from mgmt/Main.cc. - -The next step is to replace the above function calls with StatProcessor:: -processStat(). - -This statistics processor is a rather complicated module in traffic manager. -Hence it can't be easily tested. We divided the test into multiple sections. - -1) Node-based Simple Aggregation - - simply performs those aggregation that are node-based and the aggregation - is performed every time statProcess() is invoked. - E.g.: hit rate = doc. hit / doc. served. - -2) Node-based Time-Delta Aggregation - - performs those aggregation that are node-based but the operation is only - perform in a regular interval AND one of more variables in the - calculation is obtained by calculating the difference between the last - updated value and the current value. E.g. average connections per second - is calculated by subtracting the 10 seconds ago connection count from the - current connection count and divide the quotient by 10. - -Repeat the about 2 testes with cluster-based variables. So, we have, at least, -4 test cases. - -Developing a PASS/FAIL unit test that will test the statistics processor is not -cost-efficient. The approach we are going to use is to display the input value -and the output value before and after the calculation is done. - -Let's subdivide the testes in two stages: - -Stage 1 : Synthetic Data ------------------------- -We control the testing environment by setting the input values. This will test -the correctness of the statistics processor in a controlled environment. PASS/ -FAIL is determined by matching the input/output values. - -Stage 2 : Load Data -------------------- -Submitting network traffic through traffic server with load tools like jtest and -ftest, dumps the statistics to a text file, periodically and examines the -resulting values - -//----------------------------------------------------------------------------- -// For QA Engineer -//----------------------------------------------------------------------------- -The most concerning question for QA engineers is "how can I tell if the -Statistics Processor is working correctly?" - -Recall, the new Statistics Processor is meant to replace the StatAggregate.cc -and part of the WebOverview.cc. In essence, you should not see any apparent -change. - -If you ever see a value of -9999.0 (or -9999), then there is an error in -computing that value. - - -<expr> - - %d - - %f - - %k - -<dst> - - specifies the variable that stores that result value. - - ATTRIBUTE: type - built-in: variables that are built-in/defined in traffic server - custom: variables that are introducted to be temporary storage or - variables that are introdcuted by the client. - - default attributes: - type = built-in - -<src> - - variable need to computer the <dst> - - ATTRIBUTE: type - node: this is a proxy.node.* variables - cluster: the is a proxy.node.* variables but summing over all - nodes in the cluster. - - default attributes: - type = node - -<min> - - specifics what is the smallest possible value for <dst>. For values - smaller than <min>, the <defualt> is used. - -<max> - - specifics what is the largest possible value for <dst>. For values - larger than <max>, the <defualt> is used. - -<default> - - specifics what value to be assigned to <dst> is the result <dst> - value is smaller then <min> or larger then <max> - -RULES: (some of these are enfored by the DTD anyways) -- all operator and operand in <expr> MUST BE separated by a single space. -- the order of the tags matters -- the order of each entry matters -- each statistics entry has have at most 1 <dst> - - -DEFINED CONSTANT (in alphabetical order) -* _BYTES_TO_MB_SCALE - * Origin: utils/WebMgmtUtils.h - * Value: (1/(1024*1024.0)) - -* _HRTIME_SECOND - * Origin: - * Value: - -* _MBIT_TO_KBIT_SCALE - * Origin: utils/WebMgmtUtils.h - * Value: (1000.0); - -* _PCT_TO_INTPCT_SCALE - * Origin: utils/WebMgmtUtils.h - * Value: (100.0); - -* _SECOND_TO_MILLISECOND_SCALE - * Origin: utils/WebMgmtUtils.h - * Value: (1000.0); - - - __DIFFTIME