Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 #define DEBUG false  // STOPSHIP if true
     17 #include "Log.h"
     18 
     19 #include <mutex>
     20 
     21 #include "HashableDimensionKey.h"
     22 #include "FieldValue.h"
     23 
     24 namespace android {
     25 namespace os {
     26 namespace statsd {
     27 
     28 using std::string;
     29 using std::vector;
     30 
     31 android::hash_t hashDimension(const HashableDimensionKey& value) {
     32     android::hash_t hash = 0;
     33     for (const auto& fieldValue : value.getValues()) {
     34         hash = android::JenkinsHashMix(hash, android::hash_type((int)fieldValue.mField.getField()));
     35         hash = android::JenkinsHashMix(hash, android::hash_type((int)fieldValue.mField.getTag()));
     36         hash = android::JenkinsHashMix(hash, android::hash_type((int)fieldValue.mValue.getType()));
     37         switch (fieldValue.mValue.getType()) {
     38             case INT:
     39                 hash = android::JenkinsHashMix(hash,
     40                                                android::hash_type(fieldValue.mValue.int_value));
     41                 break;
     42             case LONG:
     43                 hash = android::JenkinsHashMix(hash,
     44                                                android::hash_type(fieldValue.mValue.long_value));
     45                 break;
     46             case STRING:
     47                 hash = android::JenkinsHashMix(hash, static_cast<uint32_t>(std::hash<std::string>()(
     48                                                              fieldValue.mValue.str_value)));
     49                 break;
     50             case FLOAT: {
     51                 hash = android::JenkinsHashMix(hash,
     52                                                android::hash_type(fieldValue.mValue.float_value));
     53                 break;
     54             }
     55             default:
     56                 break;
     57         }
     58     }
     59     return JenkinsHashWhiten(hash);
     60 }
     61 
     62 bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values,
     63                   HashableDimensionKey* output) {
     64     size_t num_matches = 0;
     65     for (const auto& value : values) {
     66         for (size_t i = 0; i < matcherFields.size(); ++i) {
     67             const auto& matcher = matcherFields[i];
     68             // TODO: potential optimization here to break early because all fields are naturally
     69             // sorted.
     70             if (value.mField.matches(matcher)) {
     71                 output->addValue(value);
     72                 output->mutableValue(num_matches)->mField.setTag(value.mField.getTag());
     73                 output->mutableValue(num_matches)->mField.setField(
     74                     value.mField.getField() & matcher.mMask);
     75                 num_matches++;
     76             }
     77         }
     78     }
     79     return num_matches > 0;
     80 }
     81 
     82 void filterGaugeValues(const std::vector<Matcher>& matcherFields,
     83                        const std::vector<FieldValue>& values, std::vector<FieldValue>* output) {
     84     for (const auto& field : matcherFields) {
     85         for (const auto& value : values) {
     86             if (value.mField.matches(field)) {
     87                 output->push_back(value);
     88             }
     89         }
     90     }
     91 }
     92 
     93 void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
     94                               const Metric2Condition& links,
     95                               HashableDimensionKey* conditionDimension) {
     96     // Get the dimension first by using dimension from what.
     97     filterValues(links.metricFields, eventValues, conditionDimension);
     98 
     99     size_t count = conditionDimension->getValues().size();
    100     if (count != links.conditionFields.size()) {
    101         // ALOGE("WTF condition link is bad");
    102         return;
    103     }
    104 
    105     for (size_t i = 0; i < count; i++) {
    106         conditionDimension->mutableValue(i)->mField.setField(
    107             links.conditionFields[i].mMatcher.getField());
    108         conditionDimension->mutableValue(i)->mField.setTag(
    109             links.conditionFields[i].mMatcher.getTag());
    110     }
    111 }
    112 
    113 bool LessThan(const vector<FieldValue>& s1, const vector<FieldValue>& s2) {
    114     if (s1.size() != s2.size()) {
    115         return s1.size() < s2.size();
    116     }
    117 
    118     size_t count = s1.size();
    119     for (size_t i = 0; i < count; i++) {
    120         if (s1[i] != s2[i]) {
    121             return s1[i] < s2[i];
    122         }
    123     }
    124     return false;
    125 }
    126 
    127 bool HashableDimensionKey::operator==(const HashableDimensionKey& that) const {
    128     if (mValues.size() != that.getValues().size()) {
    129         return false;
    130     }
    131     size_t count = mValues.size();
    132     for (size_t i = 0; i < count; i++) {
    133         if (mValues[i] != (that.getValues())[i]) {
    134             return false;
    135         }
    136     }
    137     return true;
    138 };
    139 
    140 bool HashableDimensionKey::operator<(const HashableDimensionKey& that) const {
    141     return LessThan(getValues(), that.getValues());
    142 };
    143 
    144 bool HashableDimensionKey::contains(const HashableDimensionKey& that) const {
    145     if (mValues.size() < that.getValues().size()) {
    146         return false;
    147     }
    148 
    149     if (mValues.size() == that.getValues().size()) {
    150         return (*this) == that;
    151     }
    152 
    153     for (const auto& value : that.getValues()) {
    154         bool found = false;
    155         for (const auto& myValue : mValues) {
    156             if (value.mField == myValue.mField && value.mValue == myValue.mValue) {
    157                 found = true;
    158                 break;
    159             }
    160         }
    161         if (!found) {
    162             return false;
    163         }
    164     }
    165 
    166     return true;
    167 }
    168 
    169 string HashableDimensionKey::toString() const {
    170     std::string output;
    171     for (const auto& value : mValues) {
    172         output += StringPrintf("(%d)%#x->%s ", value.mField.getTag(), value.mField.getField(),
    173                                value.mValue.toString().c_str());
    174     }
    175     return output;
    176 }
    177 
    178 bool MetricDimensionKey::operator==(const MetricDimensionKey& that) const {
    179     return mDimensionKeyInWhat == that.getDimensionKeyInWhat() &&
    180            mDimensionKeyInCondition == that.getDimensionKeyInCondition();
    181 };
    182 
    183 string MetricDimensionKey::toString() const {
    184     return mDimensionKeyInWhat.toString() + mDimensionKeyInCondition.toString();
    185 }
    186 
    187 bool MetricDimensionKey::operator<(const MetricDimensionKey& that) const {
    188     if (mDimensionKeyInWhat < that.getDimensionKeyInWhat()) {
    189         return true;
    190     } else if (that.getDimensionKeyInWhat() < mDimensionKeyInWhat) {
    191         return false;
    192     }
    193 
    194     return mDimensionKeyInCondition < that.getDimensionKeyInCondition();
    195 }
    196 
    197 }  // namespace statsd
    198 }  // namespace os
    199 }  // namespace android