summaryrefslogtreecommitdiff
path: root/statsd/src/socket/LogEventFilter.h
diff options
context:
space:
mode:
Diffstat (limited to 'statsd/src/socket/LogEventFilter.h')
-rw-r--r--statsd/src/socket/LogEventFilter.h129
1 files changed, 129 insertions, 0 deletions
diff --git a/statsd/src/socket/LogEventFilter.h b/statsd/src/socket/LogEventFilter.h
new file mode 100644
index 00000000..c6f7c935
--- /dev/null
+++ b/statsd/src/socket/LogEventFilter.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <gtest/gtest_prod.h>
+
+#include <atomic>
+#include <mutex>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Templating is for benchmarks only
+ *
+ * Based on benchmarks the more fast container to be used for atom ids filtering
+ * is unordered_set<int>
+ * #BM_LogEventFilterUnorderedSet 391208 ns 390086 ns 1793
+ * #BM_LogEventFilterUnorderedSet2Consumers 1293527 ns 1289326 ns 543
+ * #BM_LogEventFilterSet 613362 ns 611259 ns 1146
+ * #BM_LogEventFilterSet2Consumers 1859397 ns 1854193 ns 378
+ *
+ * See @LogEventFilter definition below
+ */
+template <typename T>
+class LogEventFilterGeneric {
+public:
+ virtual ~LogEventFilterGeneric() = default;
+
+ virtual void setFilteringEnabled(bool isEnabled) {
+ mLogsFilteringEnabled = isEnabled;
+ }
+
+ /**
+ * @brief Tests atom id with list of interesting atoms
+ * If Logs filtering is disabled - assume all atoms in use
+ * Most of the time should be non-blocking call - only in case when setAtomIds() was
+ * called the call will be blocking due to atom list needs to be synced up
+ * @param atomId
+ * @return true if atom is used by any of consumer or filtering is disabled
+ */
+ virtual bool isAtomInUse(int atomId) const {
+ if (!mLogsFilteringEnabled) {
+ return true;
+ }
+
+ // check if there is an updated set of interesting atom ids
+ if (mLocalSetUpdateCounter != mSetUpdateCounter.load(std::memory_order_relaxed)) {
+ std::lock_guard<std::mutex> guard(mTagIdsMutex);
+ mLocalSetUpdateCounter = mSetUpdateCounter.load(std::memory_order_relaxed);
+ mLocalTagIds.swap(mTagIds);
+ }
+ return mLocalTagIds.find(atomId) != mLocalTagIds.end();
+ }
+
+ typedef const void* ConsumerId;
+
+ typedef T AtomIdSet;
+ /**
+ * @brief Set the Atom Ids object
+ *
+ * @param tagIds set of atoms ids
+ * @param consumer used to differentiate the consumers to form proper superset of ids
+ */
+ virtual void setAtomIds(AtomIdSet tagIds, ConsumerId consumer) {
+ std::lock_guard lock(mTagIdsMutex);
+ // update ids list from consumer
+ if (tagIds.size() == 0) {
+ mTagIdsPerConsumer.erase(consumer);
+ } else {
+ mTagIdsPerConsumer[consumer].swap(tagIds);
+ }
+ // populate the superset incorporating list of distinct atom ids from all consumers
+ mTagIds.clear();
+ for (const auto& [_, atomIds] : mTagIdsPerConsumer) {
+ mTagIds.insert(atomIds.begin(), atomIds.end());
+ }
+ mSetUpdateCounter.fetch_add(1, std::memory_order_relaxed);
+ }
+
+private:
+ std::atomic_bool mLogsFilteringEnabled = true;
+ std::atomic_int mSetUpdateCounter;
+ mutable int mLocalSetUpdateCounter;
+
+ mutable std::mutex mTagIdsMutex;
+ std::unordered_map<ConsumerId, AtomIdSet> mTagIdsPerConsumer;
+ mutable AtomIdSet mTagIds;
+ mutable AtomIdSet mLocalTagIds;
+
+ friend class LogEventFilterTest;
+
+ FRIEND_TEST(LogEventFilterTest, TestEmptyFilter);
+ FRIEND_TEST(LogEventFilterTest, TestRemoveNonExistingEmptyFilter);
+ FRIEND_TEST(LogEventFilterTest, TestEmptyFilterDisabled);
+ FRIEND_TEST(LogEventFilterTest, TestEmptyFilterDisabledSetter);
+ FRIEND_TEST(LogEventFilterTest, TestNonEmptyFilterFullOverlap);
+ FRIEND_TEST(LogEventFilterTest, TestNonEmptyFilterPartialOverlap);
+ FRIEND_TEST(LogEventFilterTest, TestNonEmptyFilterDisabled);
+ FRIEND_TEST(LogEventFilterTest, TestNonEmptyFilterDisabledPartialOverlap);
+ FRIEND_TEST(LogEventFilterTest, TestMultipleConsumerOverlapIds);
+ FRIEND_TEST(LogEventFilterTest, TestMultipleConsumerNonOverlapIds);
+ FRIEND_TEST(LogEventFilterTest, TestMultipleConsumerOverlapIdsRemoved);
+ FRIEND_TEST(LogEventFilterTest, TestMultipleConsumerNonOverlapIdsRemoved);
+ FRIEND_TEST(LogEventFilterTest, TestMultipleConsumerEmptyFilter);
+};
+
+typedef LogEventFilterGeneric<std::unordered_set<int>> LogEventFilter;
+
+} // namespace statsd
+} // namespace os
+} // namespace android