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