Merge "[ui] Roll stable" into main
diff --git a/Android.bp b/Android.bp
index e6cf71f..430b10a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -10931,7 +10931,7 @@
name: "perfetto_src_trace_processor_db_column_column",
srcs: [
"src/trace_processor/db/column/arrangement_overlay.cc",
- "src/trace_processor/db/column/column.cc",
+ "src/trace_processor/db/column/data_node.cc",
"src/trace_processor/db/column/dense_null_overlay.cc",
"src/trace_processor/db/column/dummy_storage.cc",
"src/trace_processor/db/column/id_storage.cc",
@@ -11960,6 +11960,7 @@
"src/trace_processor/perfetto_sql/stdlib/android/broadcasts.sql",
"src/trace_processor/perfetto_sql/stdlib/android/dvfs.sql",
"src/trace_processor/perfetto_sql/stdlib/android/garbage_collection.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/input.sql",
"src/trace_processor/perfetto_sql/stdlib/android/io.sql",
"src/trace_processor/perfetto_sql/stdlib/android/monitor_contention.sql",
"src/trace_processor/perfetto_sql/stdlib/android/network_packets.sql",
diff --git a/BUILD b/BUILD
index 9460a5e..702ce4d 100644
--- a/BUILD
+++ b/BUILD
@@ -1290,8 +1290,8 @@
srcs = [
"src/trace_processor/db/column/arrangement_overlay.cc",
"src/trace_processor/db/column/arrangement_overlay.h",
- "src/trace_processor/db/column/column.cc",
- "src/trace_processor/db/column/column.h",
+ "src/trace_processor/db/column/data_node.cc",
+ "src/trace_processor/db/column/data_node.h",
"src/trace_processor/db/column/dense_null_overlay.cc",
"src/trace_processor/db/column/dense_null_overlay.h",
"src/trace_processor/db/column/dummy_storage.cc",
@@ -2264,6 +2264,7 @@
"src/trace_processor/perfetto_sql/stdlib/android/broadcasts.sql",
"src/trace_processor/perfetto_sql/stdlib/android/dvfs.sql",
"src/trace_processor/perfetto_sql/stdlib/android/garbage_collection.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/input.sql",
"src/trace_processor/perfetto_sql/stdlib/android/io.sql",
"src/trace_processor/perfetto_sql/stdlib/android/monitor_contention.sql",
"src/trace_processor/perfetto_sql/stdlib/android/network_packets.sql",
diff --git a/src/trace_processor/db/column/BUILD.gn b/src/trace_processor/db/column/BUILD.gn
index d5fa718..6bae901 100644
--- a/src/trace_processor/db/column/BUILD.gn
+++ b/src/trace_processor/db/column/BUILD.gn
@@ -18,8 +18,8 @@
sources = [
"arrangement_overlay.cc",
"arrangement_overlay.h",
- "column.cc",
- "column.h",
+ "data_node.cc",
+ "data_node.h",
"dense_null_overlay.cc",
"dense_null_overlay.h",
"dummy_storage.cc",
@@ -44,6 +44,7 @@
"../..:metatrace",
"../../../../gn:default_deps",
"../../../../include/perfetto/trace_processor:basic_types",
+ "../../../../include/perfetto/trace_processor:trace_processor",
"../../../../protos/perfetto/trace_processor:zero",
"../../../base",
"../../containers",
@@ -86,6 +87,7 @@
"../../../../gn:default_deps",
"../../../../gn:gtest_and_gmock",
"../../../../include/perfetto/trace_processor:basic_types",
+ "../../../base",
"../../containers",
]
}
diff --git a/src/trace_processor/db/column/arrangement_overlay.cc b/src/trace_processor/db/column/arrangement_overlay.cc
index 1af8504..1742d40 100644
--- a/src/trace_processor/db/column/arrangement_overlay.cc
+++ b/src/trace_processor/db/column/arrangement_overlay.cc
@@ -18,42 +18,62 @@
#include <algorithm>
#include <cstdint>
+#include <memory>
+#include <utility>
#include <vector>
-#include "protos/perfetto/trace_processor/serialization.pbzero.h"
+#include "perfetto/base/logging.h"
+#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/tp_metatrace.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
-namespace {} // namespace
+#include "protos/perfetto/trace_processor/metatrace_categories.pbzero.h"
+#include "protos/perfetto/trace_processor/serialization.pbzero.h"
-ArrangementOverlay::ArrangementOverlay(std::unique_ptr<Column> inner,
- const std::vector<uint32_t>* arrangement,
+namespace perfetto::trace_processor::column {
+
+ArrangementOverlay::ArrangementOverlay(const std::vector<uint32_t>* arrangement,
bool does_arrangement_order_storage)
- : inner_(std::move(inner)),
- arrangement_(arrangement),
+ : arrangement_(arrangement),
arrangement_state_(
std::is_sorted(arrangement->begin(), arrangement->end())
? Indices::State::kMonotonic
: Indices::State::kNonmonotonic),
+ does_arrangement_order_storage_(does_arrangement_order_storage) {}
+
+std::unique_ptr<DataNode::Queryable> ArrangementOverlay::MakeQueryable(
+ std::unique_ptr<DataNode::Queryable> inner) {
+ return std::make_unique<Queryable>(std::move(inner), arrangement_,
+ arrangement_state_,
+ does_arrangement_order_storage_);
+}
+
+ArrangementOverlay::Queryable::Queryable(
+ std::unique_ptr<DataNode::Queryable> inner,
+ const std::vector<uint32_t>* arrangement,
+ Indices::State arrangement_state,
+ bool does_arrangement_order_storage)
+ : inner_(std::move(inner)),
+ arrangement_(arrangement),
+ arrangement_state_(arrangement_state),
does_arrangement_order_storage_(does_arrangement_order_storage) {
PERFETTO_DCHECK(*std::max_element(arrangement->begin(), arrangement->end()) <=
inner_->size());
}
-SearchValidationResult ArrangementOverlay::ValidateSearchConstraints(
+SearchValidationResult ArrangementOverlay::Queryable::ValidateSearchConstraints(
SqlValue sql_val,
FilterOp op) const {
return inner_->ValidateSearchConstraints(sql_val, op);
}
-RangeOrBitVector ArrangementOverlay::Search(FilterOp op,
- SqlValue sql_val,
- Range in) const {
- PERFETTO_TP_TRACE(metatrace::Category::DB, "ArrangementOverlay::Search");
+RangeOrBitVector ArrangementOverlay::Queryable::Search(FilterOp op,
+ SqlValue sql_val,
+ Range in) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB,
+ "ArrangementOverlay::Queryable::Search");
if (does_arrangement_order_storage_ && op != FilterOp::kGlob &&
op != FilterOp::kRegex) {
@@ -110,10 +130,12 @@
return RangeOrBitVector(std::move(builder).Build());
}
-RangeOrBitVector ArrangementOverlay::IndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
- PERFETTO_TP_TRACE(metatrace::Category::DB, "ArrangementOverlay::IndexSearch");
+RangeOrBitVector ArrangementOverlay::Queryable::IndexSearch(
+ FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB,
+ "ArrangementOverlay::Queryable::IndexSearch");
std::vector<uint32_t> storage_iv(indices.size);
// Should be SIMD optimized.
@@ -136,17 +158,17 @@
Indices::State::kNonmonotonic});
}
-void ArrangementOverlay::StableSort(uint32_t*, uint32_t) const {
+void ArrangementOverlay::Queryable::StableSort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_FATAL("Not implemented");
}
-void ArrangementOverlay::Sort(uint32_t*, uint32_t) const {
+void ArrangementOverlay::Queryable::Sort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_FATAL("Not implemented");
}
-void ArrangementOverlay::Serialize(StorageProto* storage) const {
+void ArrangementOverlay::Queryable::Serialize(StorageProto* storage) const {
auto* arrangement_overlay = storage->set_arrangement_overlay();
arrangement_overlay->set_values(
reinterpret_cast<const uint8_t*>(arrangement_->data()),
@@ -154,6 +176,4 @@
inner_->Serialize(arrangement_overlay->set_storage());
}
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/arrangement_overlay.h b/src/trace_processor/db/column/arrangement_overlay.h
index 233ca6a..9de7fd4 100644
--- a/src/trace_processor/db/column/arrangement_overlay.h
+++ b/src/trace_processor/db/column/arrangement_overlay.h
@@ -24,56 +24,66 @@
#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/basic_types.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+namespace perfetto::trace_processor::column {
// Storage responsible for rearranging the elements of another Storage. It deals
// with duplicates, permutations and selection; for selection only, it's more
// efficient to use `SelectorOverlay`.
-class ArrangementOverlay : public Column {
+class ArrangementOverlay : public DataNode {
public:
- explicit ArrangementOverlay(std::unique_ptr<Column> inner,
- const std::vector<uint32_t>* arrangement,
- bool does_arrangement_order_storage);
+ ArrangementOverlay(const std::vector<uint32_t>* arrangement,
+ bool does_arrangement_order_storage);
- SearchValidationResult ValidateSearchConstraints(SqlValue,
- FilterOp) const override;
-
- RangeOrBitVector Search(FilterOp op,
- SqlValue value,
- Range range) const override;
-
- RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
-
- Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override {
- PERFETTO_FATAL("OrderedIndexSearch can't be called on ArrangementOverlay");
- }
-
- void StableSort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Sort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Serialize(StorageProto*) const override;
-
- uint32_t size() const override {
- return static_cast<uint32_t>(arrangement_->size());
- }
-
- std::string DebugString() const override { return "ArrangementOverlay"; }
+ std::unique_ptr<Queryable> MakeQueryable(std::unique_ptr<Queryable>) override;
private:
- std::unique_ptr<Column> inner_;
+ class Queryable : public DataNode::Queryable {
+ public:
+ Queryable(std::unique_ptr<DataNode::Queryable> inner,
+ const std::vector<uint32_t>* arrangement,
+ Indices::State arrangement_state,
+ bool does_arrangement_order_storage);
+
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
+ RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
+
+ RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override {
+ PERFETTO_FATAL(
+ "OrderedIndexSearch can't be called on ArrangementOverlay");
+ }
+
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Sort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ uint32_t size() const override {
+ return static_cast<uint32_t>(arrangement_->size());
+ }
+
+ std::string DebugString() const override { return "ArrangementOverlay"; }
+
+ private:
+ std::unique_ptr<DataNode::Queryable> inner_;
+ const std::vector<uint32_t>* arrangement_;
+ const Indices::State arrangement_state_;
+ const bool does_arrangement_order_storage_;
+ };
+
+ std::unique_ptr<DataNode::Queryable> inner_;
const std::vector<uint32_t>* arrangement_;
const Indices::State arrangement_state_;
const bool does_arrangement_order_storage_;
};
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
#endif // SRC_TRACE_PROCESSOR_DB_COLUMN_ARRANGEMENT_OVERLAY_H_
diff --git a/src/trace_processor/db/column/arrangement_overlay_unittest.cc b/src/trace_processor/db/column/arrangement_overlay_unittest.cc
index 4b1617f..b724ffc 100644
--- a/src/trace_processor/db/column/arrangement_overlay_unittest.cc
+++ b/src/trace_processor/db/column/arrangement_overlay_unittest.cc
@@ -16,14 +16,17 @@
#include "src/trace_processor/db/column/arrangement_overlay.h"
+#include <cstdint>
+#include <vector>
+
+#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/db/column/fake_storage.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/column/utils.h"
#include "test/gtest_and_gmock.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+namespace perfetto::trace_processor::column {
namespace {
using testing::ElementsAre;
@@ -31,49 +34,56 @@
TEST(ArrangementOverlay, SearchAll) {
std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- ArrangementOverlay storage(FakeStorage::SearchAll(5), &arrangement, false);
+ auto fake = FakeStorage::SearchAll(5);
+ ArrangementOverlay storage(&arrangement, false);
+ auto queriable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0u), Range(2, 4));
+ auto res = queriable->Search(FilterOp::kGe, SqlValue::Long(0u), Range(2, 4));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2u, 3u));
}
TEST(ArrangementOverlay, SearchNone) {
std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- ArrangementOverlay storage(FakeStorage::SearchNone(5), &arrangement, false);
+ auto fake = FakeStorage::SearchNone(5);
+ ArrangementOverlay storage(&arrangement, false);
+ auto queriable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0u), Range(2, 4));
+ auto res = queriable->Search(FilterOp::kGe, SqlValue::Long(0u), Range(2, 4));
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
}
TEST(ArrangementOverlay, DISABLED_SearchLimited) {
std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- ArrangementOverlay storage(FakeStorage::SearchSubset(5, Range(4, 5)),
- &arrangement, false);
+ auto fake = FakeStorage::SearchSubset(5, Range(4, 5));
+ ArrangementOverlay storage(&arrangement, false);
+ auto queriable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0u), Range(2, 7));
+ auto res = queriable->Search(FilterOp::kGe, SqlValue::Long(0u), Range(2, 7));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(6u));
}
TEST(ArrangementOverlay, SearchBitVector) {
std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- ArrangementOverlay storage(
- FakeStorage::SearchSubset(5, BitVector({0, 1, 0, 1, 0})), &arrangement,
- false);
+ auto fake = FakeStorage::SearchSubset(
+ 5, BitVector({false, true, false, true, false}));
+ ArrangementOverlay storage(&arrangement, false);
+ auto queriable = storage.MakeQueryable(fake->MakeQueryable());
// Table bv:
// 1, 1, 0, 0, 1, 1, 0, 0, 1, 1
- auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 10));
+ auto res = queriable->Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 10));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 4, 5, 8, 9));
}
TEST(ArrangementOverlay, IndexSearch) {
std::vector<uint32_t> arrangement{1, 1, 2, 2, 3, 3, 4, 4, 1, 1};
- ArrangementOverlay storage(
- FakeStorage::SearchSubset(5, BitVector({0, 1, 0, 1, 0})), &arrangement,
- false);
+ auto fake = FakeStorage::SearchSubset(
+ 5, BitVector({false, true, false, true, false}));
+ ArrangementOverlay storage(&arrangement, false);
+ auto queriable = storage.MakeQueryable(fake->MakeQueryable());
std::vector<uint32_t> table_idx{7u, 1u, 3u};
- RangeOrBitVector res = storage.IndexSearch(
+ RangeOrBitVector res = queriable->IndexSearch(
FilterOp::kGe, SqlValue::Long(0u),
Indices{table_idx.data(), static_cast<uint32_t>(table_idx.size()),
Indices::State::kNonmonotonic});
@@ -83,17 +93,16 @@
TEST(ArrangementOverlay, OrderingSearch) {
std::vector<uint32_t> arrangement{0, 2, 4, 1, 3};
- ArrangementOverlay storage(
- FakeStorage::SearchSubset(5, BitVector({0, 1, 0, 1, 0})), &arrangement,
- true);
+ auto fake = FakeStorage::SearchSubset(
+ 5, BitVector({false, true, false, true, false}));
+ ArrangementOverlay storage(&arrangement, true);
+ auto queriable = storage.MakeQueryable(fake->MakeQueryable());
RangeOrBitVector res =
- storage.Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 5));
+ queriable->Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 5));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
}
} // namespace
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/column.h b/src/trace_processor/db/column/column.h
deleted file mode 100644
index 9232d8f..0000000
--- a/src/trace_processor/db/column/column.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.
- */
-#ifndef SRC_TRACE_PROCESSOR_DB_COLUMN_COLUMN_H_
-#define SRC_TRACE_PROCESSOR_DB_COLUMN_COLUMN_H_
-
-#include <cstdint>
-#include <string>
-
-#include "perfetto/trace_processor/basic_types.h"
-#include "src/trace_processor/db/column/types.h"
-
-namespace perfetto {
-namespace protos::pbzero {
-class SerializedColumn_Storage;
-}
-
-namespace trace_processor::column {
-
-// Defines an API of a Column. Storages and Overlays both inherit from
-// Column.
-class Column {
- public:
- using StorageProto = protos::pbzero::SerializedColumn_Storage;
-
- virtual ~Column();
-
- // Verifies whether any further filtering is needed and if not, whether the
- // search would return all values or none of them. This allows for skipping
- // the |Search| and |IndexSearch| in special cases.
- //
- // Notes for callers:
- // * The SqlValue and FilterOp have to be valid in Sqlite: it will crash if
- // either: value is NULL and operation is different than "IS NULL" and "IS
- // NOT NULL" or the operation is "IS NULL" and "IS NOT NULL" and value is
- // different than NULL.
- virtual SearchValidationResult ValidateSearchConstraints(SqlValue,
- FilterOp) const = 0;
-
- // Searches for elements which match |op| and |value| between |range.start|
- // and |range.end|.
- //
- // Returns either a range or BitVector which indicate the positions in |range|
- // which match the constraint. If a BitVector is returned, it will be
- // *precisely* as large as |range.end|.
- //
- // Notes for callers:
- // * Should only be called if ValidateSearchContraints returned kOk.
- // * Callers should note that the return value of this function corresponds
- // to positions in the storage.
- //
- // Notes for implementors:
- // * Implementations should ensure that the return value *only* includes
- // positions in |range| as callers will expect this to be true and can
- // optimize based on this.
- // * Implementations should ensure that, if they return a BitVector, it is
- // precisely of size |range.end|.
- virtual RangeOrBitVector Search(FilterOp, SqlValue, Range) const = 0;
-
- // Searches for elements which match |op| and |value| at the positions given
- // by |indices| array.
- //
- // Returns either a range of BitVector which indicate the positions in
- // |indices| which match the constraint. If a BitVector is returned, it will
- // be *precisely* as large as |indices_count|.
- //
- // Notes for callers:
- // * Should only be called if ValidateSearchContraints returned kOk.
- // * Callers should note that the return value of this function corresponds
- // to positions in |indices| *not* positions in the storage.
- //
- // Notes for implementors:
- // * Implementations should ensure that, if they return a BitVector, it is
- // precisely of size |indices_count|.
- virtual RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const = 0;
-
- // Searches for elements which match |op| and |value| at the positions given
- // by indices data.
- //
- // Returns a Range into Indices data of indices that pass the constraint.
- //
- // Notes for callers:
- // * Should not be called on:
- // - kGlob and kRegex as those operations can't use the sorted state hence
- // they can't return a Range.
- // - kNe as this is inherently unsorted. Use kEq and then reverse the
- // result.
- // * Should only be called if ValidateSearchContraints returned kOk.
- // * Callers should note that the return value of this function corresponds
- // to positions in |indices| *not* positions in the storage.
- virtual Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const = 0;
-
- // Sorts |rows| in ascending order with the comparator:
- // data[rows[a]] < data[rows[b]].
- virtual void Sort(uint32_t* rows, uint32_t rows_size) const = 0;
-
- // Stable sorts |rows| in ascending order with the comparator:
- // data[rows[a]] < data[rows[b]].
- virtual void StableSort(uint32_t* rows, uint32_t rows_size) const = 0;
-
- // Serializes storage data to proto format.
- virtual void Serialize(StorageProto*) const = 0;
-
- // Returns a string which represents the column for debugging purposes.
- //
- // Warning: the format of the string returned by this class is *not* stable
- // and should be relied upon for anything except printing for debugging
- // purposes.
- virtual std::string DebugString() const = 0;
-
- // Number of elements in stored data.
- virtual uint32_t size() const = 0;
-};
-
-} // namespace trace_processor::column
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_DB_COLUMN_COLUMN_H_
diff --git a/src/trace_processor/db/column/column.cc b/src/trace_processor/db/column/data_node.cc
similarity index 73%
rename from src/trace_processor/db/column/column.cc
rename to src/trace_processor/db/column/data_node.cc
index a3e62d4..22ba2dc 100644
--- a/src/trace_processor/db/column/column.cc
+++ b/src/trace_processor/db/column/data_node.cc
@@ -14,14 +14,11 @@
* limitations under the License.
*/
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+namespace perfetto::trace_processor::column {
-Column::~Column() = default;
+DataNode::~DataNode() = default;
+DataNode::Queryable::~Queryable() = default;
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/data_node.h b/src/trace_processor/db/column/data_node.h
new file mode 100644
index 0000000..89020df
--- /dev/null
+++ b/src/trace_processor/db/column/data_node.h
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_DB_COLUMN_DATA_NODE_H_
+#define SRC_TRACE_PROCESSOR_DB_COLUMN_DATA_NODE_H_
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/trace_processor/basic_types.h"
+#include "perfetto/trace_processor/ref_counted.h"
+#include "src/trace_processor/db/column/types.h"
+
+namespace perfetto {
+namespace protos::pbzero {
+class SerializedColumn_Storage;
+}
+
+namespace trace_processor::column {
+
+class DataNode : public RefCounted {
+ public:
+ class Queryable {
+ public:
+ using StorageProto = protos::pbzero::SerializedColumn_Storage;
+
+ virtual ~Queryable();
+
+ // Verifies whether any further filtering is needed and if not, whether the
+ // search would return all values or none of them. This allows for skipping
+ // the |Search| and |IndexSearch| in special cases.
+ //
+ // Notes for callers:
+ // * The SqlValue and FilterOp have to be valid in Sqlite: it will crash if
+ // either: value is NULL and operation is different than "IS NULL" and "IS
+ // NOT NULL" or the operation is "IS NULL" and "IS NOT NULL" and value is
+ // different than NULL.
+ virtual SearchValidationResult ValidateSearchConstraints(SqlValue, FilterOp)
+ const = 0;
+
+ // Searches for elements which match |op| and |value| between |range.start|
+ // and |range.end|.
+ //
+ // Returns either a range or BitVector which indicate the positions in
+ // |range| which match the constraint. If a BitVector is returned, it will
+ // be *precisely* as large as |range.end|.
+ //
+ // Notes for callers:
+ // * Should only be called if ValidateSearchContraints returned kOk.
+ // * Callers should note that the return value of this function corresponds
+ // to positions in the storage.
+ //
+ // Notes for implementors:
+ // * Implementations should ensure that the return value *only* includes
+ // positions in |range| as callers will expect this to be true and can
+ // optimize based on this.
+ // * Implementations should ensure that, if they return a BitVector, it is
+ // precisely of size |range.end|.
+ virtual RangeOrBitVector Search(FilterOp, SqlValue, Range) const = 0;
+
+ // Searches for elements which match |op| and |value| at the positions given
+ // by |indices| array.
+ //
+ // Returns either a range of BitVector which indicate the positions in
+ // |indices| which match the constraint. If a BitVector is returned, it will
+ // be *precisely* as large as |indices_count|.
+ //
+ // Notes for callers:
+ // * Should only be called if ValidateSearchContraints returned kOk.
+ // * Callers should note that the return value of this function corresponds
+ // to positions in |indices| *not* positions in the storage.
+ //
+ // Notes for implementors:
+ // * Implementations should ensure that, if they return a BitVector, it is
+ // precisely of size |indices_count|.
+ virtual RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const = 0;
+
+ // Searches for elements which match |op| and |value| at the positions given
+ // by indices data.
+ //
+ // Returns a Range into Indices data of indices that pass the constraint.
+ //
+ // Notes for callers:
+ // * Should not be called on:
+ // - kGlob and kRegex as those operations can't use the sorted state
+ // hence they can't return a Range.
+ // - kNe as this is inherently unsorted. Use kEq and then reverse the
+ // result.
+ // * Should only be called if ValidateSearchContraints returned kOk.
+ // * Callers should note that the return value of this function corresponds
+ // to positions in |indices| *not* positions in the storage.
+ virtual Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const = 0;
+
+ // Sorts |rows| in ascending order with the comparator:
+ // data[rows[a]] < data[rows[b]].
+ virtual void Sort(uint32_t* rows, uint32_t rows_size) const = 0;
+
+ // Stable sorts |rows| in ascending order with the comparator:
+ // data[rows[a]] < data[rows[b]].
+ virtual void StableSort(uint32_t* rows, uint32_t rows_size) const = 0;
+
+ // Serializes storage data to proto format.
+ virtual void Serialize(StorageProto*) const = 0;
+
+ // Returns a string which represents the column for debugging purposes.
+ //
+ // Warning: the format of the string returned by this class is *not* stable
+ // and should be relied upon for anything except printing for debugging
+ // purposes.
+ virtual std::string DebugString() const = 0;
+
+ // Number of elements in stored data.
+ virtual uint32_t size() const = 0;
+ };
+
+ virtual ~DataNode();
+
+ virtual std::unique_ptr<Queryable> MakeQueryable() {
+ PERFETTO_FATAL("Unimplemented");
+ }
+ virtual std::unique_ptr<Queryable> MakeQueryable(std::unique_ptr<Queryable>) {
+ PERFETTO_FATAL("Unimplemented");
+ }
+};
+
+} // namespace trace_processor::column
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_DB_COLUMN_DATA_NODE_H_
diff --git a/src/trace_processor/db/column/dense_null_overlay.cc b/src/trace_processor/db/column/dense_null_overlay.cc
index e1e6b98..ac07d3f 100644
--- a/src/trace_processor/db/column/dense_null_overlay.cc
+++ b/src/trace_processor/db/column/dense_null_overlay.cc
@@ -25,7 +25,7 @@
#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/tp_metatrace.h"
@@ -34,11 +34,20 @@
namespace perfetto::trace_processor::column {
-DenseNullOverlay::DenseNullOverlay(std::unique_ptr<Column> inner,
- const BitVector* non_null)
+DenseNullOverlay::DenseNullOverlay(const BitVector* non_null)
+ : non_null_(non_null) {}
+
+std::unique_ptr<DataNode::Queryable> DenseNullOverlay::MakeQueryable(
+ std::unique_ptr<DataNode::Queryable> inner) {
+ return std::make_unique<Queryable>(std::move(inner), non_null_);
+}
+
+DenseNullOverlay::Queryable::Queryable(
+ std::unique_ptr<DataNode::Queryable> inner,
+ const BitVector* non_null)
: inner_(std::move(inner)), non_null_(non_null) {}
-SearchValidationResult DenseNullOverlay::ValidateSearchConstraints(
+SearchValidationResult DenseNullOverlay::Queryable::ValidateSearchConstraints(
SqlValue sql_val,
FilterOp op) const {
if (op == FilterOp::kIsNull) {
@@ -48,10 +57,11 @@
return inner_->ValidateSearchConstraints(sql_val, op);
}
-RangeOrBitVector DenseNullOverlay::Search(FilterOp op,
- SqlValue sql_val,
- Range in) const {
- PERFETTO_TP_TRACE(metatrace::Category::DB, "DenseNullOverlay::Search");
+RangeOrBitVector DenseNullOverlay::Queryable::Search(FilterOp op,
+ SqlValue sql_val,
+ Range in) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB,
+ "DenseNullOverlay::Queryable::Search");
if (op == FilterOp::kIsNull) {
switch (inner_->ValidateSearchConstraints(sql_val, op)) {
@@ -103,10 +113,12 @@
return RangeOrBitVector(std::move(res));
}
-RangeOrBitVector DenseNullOverlay::IndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
- PERFETTO_TP_TRACE(metatrace::Category::DB, "DenseNullOverlay::IndexSearch");
+RangeOrBitVector DenseNullOverlay::Queryable::IndexSearch(
+ FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB,
+ "DenseNullOverlay::Queryable::IndexSearch");
if (op == FilterOp::kIsNull) {
switch (inner_->ValidateSearchConstraints(sql_val, op)) {
@@ -157,14 +169,14 @@
return RangeOrBitVector(std::move(res));
}
-Range DenseNullOverlay::OrderedIndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+Range DenseNullOverlay::Queryable::OrderedIndexSearch(FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
// For NOT EQUAL the further analysis needs to be done by the caller.
PERFETTO_CHECK(op != FilterOp::kNe);
PERFETTO_TP_TRACE(metatrace::Category::DB,
- "DenseNullOverlay::OrderedIndexSearch");
+ "DenseNullOverlay::Queryable::OrderedIndexSearch");
// We assume all NULLs are ordered to be in the front. We are looking for the
// first index that points to non NULL value.
@@ -199,17 +211,17 @@
inner_range.end + non_null_offset);
}
-void DenseNullOverlay::StableSort(uint32_t*, uint32_t) const {
+void DenseNullOverlay::Queryable::StableSort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_FATAL("Not implemented");
}
-void DenseNullOverlay::Sort(uint32_t*, uint32_t) const {
+void DenseNullOverlay::Queryable::Sort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_FATAL("Not implemented");
}
-void DenseNullOverlay::Serialize(StorageProto* storage) const {
+void DenseNullOverlay::Queryable::Serialize(StorageProto* storage) const {
auto* null_overlay = storage->set_dense_null_overlay();
non_null_->Serialize(null_overlay->set_bit_vector());
inner_->Serialize(null_overlay->set_storage());
diff --git a/src/trace_processor/db/column/dense_null_overlay.h b/src/trace_processor/db/column/dense_null_overlay.h
index 9b473fc..d2b341b 100644
--- a/src/trace_processor/db/column/dense_null_overlay.h
+++ b/src/trace_processor/db/column/dense_null_overlay.h
@@ -19,49 +19,57 @@
#include <cstdint>
#include <memory>
-#include <variant>
+#include <string>
+#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+namespace perfetto::trace_processor::column {
// Overlay which introduces the layer of nullability but without changing the
// "spacing" of the underlying storage i.e. this overlay simply "masks" out
// rows in the underlying storage with nulls.
-class DenseNullOverlay : public Column {
+class DenseNullOverlay : public DataNode {
public:
- DenseNullOverlay(std::unique_ptr<Column> inner, const BitVector* non_null);
+ explicit DenseNullOverlay(const BitVector* non_null);
- SearchValidationResult ValidateSearchConstraints(SqlValue,
- FilterOp) const override;
-
- RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
-
- RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
-
- Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
-
- void StableSort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Sort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Serialize(StorageProto*) const override;
-
- uint32_t size() const override { return non_null_->size(); }
-
- std::string DebugString() const override { return "DenseNullOverlay"; }
+ std::unique_ptr<Queryable> MakeQueryable(std::unique_ptr<Queryable>) override;
private:
- std::unique_ptr<Column> inner_;
+ class Queryable : public DataNode::Queryable {
+ public:
+ Queryable(std::unique_ptr<DataNode::Queryable> inner,
+ const BitVector* non_null);
+
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
+ RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
+
+ RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Sort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ uint32_t size() const override { return non_null_->size(); }
+
+ std::string DebugString() const override { return "DenseNullOverlay"; }
+
+ private:
+ std::unique_ptr<DataNode::Queryable> inner_;
+ const BitVector* non_null_ = nullptr;
+ };
+
const BitVector* non_null_ = nullptr;
};
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
#endif // SRC_TRACE_PROCESSOR_DB_COLUMN_DENSE_NULL_OVERLAY_H_
diff --git a/src/trace_processor/db/column/dense_null_overlay_unittest.cc b/src/trace_processor/db/column/dense_null_overlay_unittest.cc
index 871e424..5067b2d 100644
--- a/src/trace_processor/db/column/dense_null_overlay_unittest.cc
+++ b/src/trace_processor/db/column/dense_null_overlay_unittest.cc
@@ -43,9 +43,10 @@
std::make_unique<NumericStorage<uint32_t>>(&data, ColumnType::kUint32);
BitVector bv{0, 1, 0, 1, 0};
- DenseNullOverlay storage(std::move(numeric), &bv);
+ DenseNullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(numeric->MakeQueryable());
- auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0), Range(0, 5));
+ auto res = queryable->Search(FilterOp::kGe, SqlValue::Long(0), Range(0, 5));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 3));
}
@@ -55,9 +56,10 @@
std::make_unique<NumericStorage<uint32_t>>(&data, ColumnType::kUint32);
BitVector bv{0, 1, 0, 1, 0};
- DenseNullOverlay storage(std::move(numeric), &bv);
+ DenseNullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(numeric->MakeQueryable());
- auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0), Range(1, 3));
+ auto res = queryable->Search(FilterOp::kGe, SqlValue::Long(0), Range(1, 3));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
}
@@ -65,9 +67,10 @@
auto fake = FakeStorage::SearchSubset(5, Range(1, 3));
BitVector bv{0, 1, 0, 1, 0};
- DenseNullOverlay storage(std::move(fake), &bv);
+ DenseNullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0), Range(0, 5));
+ auto res = queryable->Search(FilterOp::kGe, SqlValue::Long(0), Range(0, 5));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
}
@@ -75,9 +78,10 @@
auto fake = FakeStorage::SearchSubset(5, BitVector({0, 1, 1, 0, 0}));
BitVector bv{0, 1, 0, 1, 0};
- DenseNullOverlay storage(std::move(fake), &bv);
+ DenseNullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0), Range(0, 5));
+ auto res = queryable->Search(FilterOp::kGe, SqlValue::Long(0), Range(0, 5));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
}
@@ -85,9 +89,10 @@
auto fake = FakeStorage::SearchSubset(5, BitVector({1, 1, 0, 0, 1}));
BitVector bv{1, 0, 0, 1, 1};
- DenseNullOverlay storage(std::move(fake), &bv);
+ DenseNullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kIsNull, SqlValue(), Range(0, 5));
+ auto res = queryable->Search(FilterOp::kIsNull, SqlValue(), Range(0, 5));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 4));
}
@@ -97,10 +102,11 @@
std::make_unique<NumericStorage<uint32_t>>(&data, ColumnType::kUint32);
BitVector bv{1, 0, 0, 1, 1, 1};
- DenseNullOverlay storage(std::move(numeric), &bv);
+ DenseNullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(numeric->MakeQueryable());
std::vector<uint32_t> index({5, 2, 3, 4, 1});
- auto res = storage.IndexSearch(
+ auto res = queryable->IndexSearch(
FilterOp::kGe, SqlValue::Long(0),
Indices{index.data(), static_cast<uint32_t>(index.size()),
Indices::State::kNonmonotonic});
@@ -111,10 +117,11 @@
auto fake = FakeStorage::SearchSubset(6, BitVector({0, 0, 0, 1, 1, 1}));
BitVector bv{0, 1, 0, 1, 1, 1};
- DenseNullOverlay storage(std::move(fake), &bv);
+ DenseNullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
std::vector<uint32_t> index({5, 2, 3, 4, 1});
- auto res = storage.IndexSearch(
+ auto res = queryable->IndexSearch(
FilterOp::kIsNull, SqlValue(),
Indices{index.data(), static_cast<uint32_t>(index.size()),
Indices::State::kMonotonic});
@@ -125,37 +132,44 @@
auto fake = FakeStorage::SearchSubset(6, BitVector({0, 1, 0, 1, 0, 1}));
BitVector bv{0, 1, 0, 1, 0, 1};
- DenseNullOverlay storage(std::move(fake), &bv);
+ DenseNullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
std::vector<uint32_t> indices_vec({0, 2, 4, 1, 3, 5});
Indices indices{indices_vec.data(), 6, Indices::State::kNonmonotonic};
Range res =
- storage.OrderedIndexSearch(FilterOp::kIsNull, SqlValue(), indices);
+ queryable->OrderedIndexSearch(FilterOp::kIsNull, SqlValue(), indices);
ASSERT_EQ(res.start, 0u);
ASSERT_EQ(res.end, 3u);
- res = storage.OrderedIndexSearch(FilterOp::kIsNotNull, SqlValue(), indices);
+ res =
+ queryable->OrderedIndexSearch(FilterOp::kIsNotNull, SqlValue(), indices);
ASSERT_EQ(res.start, 3u);
ASSERT_EQ(res.end, 6u);
- res = storage.OrderedIndexSearch(FilterOp::kEq, SqlValue::Long(3), indices);
+ res =
+ queryable->OrderedIndexSearch(FilterOp::kEq, SqlValue::Long(3), indices);
ASSERT_EQ(res.start, 3u);
ASSERT_EQ(res.end, 6u);
- res = storage.OrderedIndexSearch(FilterOp::kGt, SqlValue::Long(3), indices);
+ res =
+ queryable->OrderedIndexSearch(FilterOp::kGt, SqlValue::Long(3), indices);
ASSERT_EQ(res.start, 3u);
ASSERT_EQ(res.end, 6u);
- res = storage.OrderedIndexSearch(FilterOp::kGe, SqlValue::Long(3), indices);
+ res =
+ queryable->OrderedIndexSearch(FilterOp::kGe, SqlValue::Long(3), indices);
ASSERT_EQ(res.start, 3u);
ASSERT_EQ(res.end, 6u);
- res = storage.OrderedIndexSearch(FilterOp::kLt, SqlValue::Long(3), indices);
+ res =
+ queryable->OrderedIndexSearch(FilterOp::kLt, SqlValue::Long(3), indices);
ASSERT_EQ(res.start, 3u);
ASSERT_EQ(res.end, 6u);
- res = storage.OrderedIndexSearch(FilterOp::kLe, SqlValue::Long(3), indices);
+ res =
+ queryable->OrderedIndexSearch(FilterOp::kLe, SqlValue::Long(3), indices);
ASSERT_EQ(res.start, 3u);
ASSERT_EQ(res.end, 6u);
}
diff --git a/src/trace_processor/db/column/dummy_storage.cc b/src/trace_processor/db/column/dummy_storage.cc
index df24dfa..5475cc4 100644
--- a/src/trace_processor/db/column/dummy_storage.cc
+++ b/src/trace_processor/db/column/dummy_storage.cc
@@ -15,46 +15,59 @@
*/
#include "src/trace_processor/db/column/dummy_storage.h"
-#include "protos/perfetto/trace_processor/serialization.pbzero.h"
+
+#include <cstdint>
+#include <memory>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+namespace perfetto::trace_processor::column {
-SearchValidationResult DummyStorage::ValidateSearchConstraints(SqlValue,
- FilterOp) const {
+std::unique_ptr<DataNode::Queryable> DummyStorage::MakeQueryable() {
+ return std::make_unique<Queryable>();
+}
+
+SearchValidationResult DummyStorage::Queryable::ValidateSearchConstraints(
+ SqlValue,
+ FilterOp) const {
PERFETTO_FATAL("Shouldn't be called");
}
-RangeOrBitVector DummyStorage::Search(FilterOp, SqlValue, Range) const {
+RangeOrBitVector DummyStorage::Queryable::Search(FilterOp,
+ SqlValue,
+ Range) const {
PERFETTO_FATAL("Shouldn't be called");
}
-RangeOrBitVector DummyStorage::IndexSearch(FilterOp, SqlValue, Indices) const {
+RangeOrBitVector DummyStorage::Queryable::IndexSearch(FilterOp,
+ SqlValue,
+ Indices) const {
PERFETTO_FATAL("Shouldn't be called");
}
-Range DummyStorage::OrderedIndexSearch(FilterOp, SqlValue, Indices) const {
+Range DummyStorage::Queryable::OrderedIndexSearch(FilterOp,
+ SqlValue,
+ Indices) const {
PERFETTO_FATAL("Shouldn't be called");
}
-void DummyStorage::StableSort(uint32_t*, uint32_t) const {
+void DummyStorage::Queryable::StableSort(uint32_t*, uint32_t) const {
PERFETTO_FATAL("Shouldn't be called");
}
-void DummyStorage::Sort(uint32_t*, uint32_t) const {
+void DummyStorage::Queryable::Sort(uint32_t*, uint32_t) const {
PERFETTO_FATAL("Shouldn't be called");
}
-uint32_t DummyStorage::size() const {
+uint32_t DummyStorage::Queryable::size() const {
return 0;
}
-void DummyStorage::Serialize(StorageProto*) const {
+void DummyStorage::Queryable::Serialize(StorageProto*) const {
PERFETTO_FATAL("Shouldn't be called");
}
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/dummy_storage.h b/src/trace_processor/db/column/dummy_storage.h
index 9158f6f..ab5e547 100644
--- a/src/trace_processor/db/column/dummy_storage.h
+++ b/src/trace_processor/db/column/dummy_storage.h
@@ -17,38 +17,45 @@
#define SRC_TRACE_PROCESSOR_DB_COLUMN_DUMMY_STORAGE_H_
#include <cstdint>
+#include <memory>
#include <string>
#include "perfetto/trace_processor/basic_types.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
namespace perfetto::trace_processor::column {
// Dummy storage. Used for columns that are not supposed to have operations done
// on them.
-class DummyStorage final : public Column {
+class DummyStorage final : public DataNode {
public:
- DummyStorage() = default;
+ std::unique_ptr<DataNode::Queryable> MakeQueryable() override;
- RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
+ private:
+ class Queryable : public DataNode::Queryable {
+ public:
+ Queryable() = default;
- SearchValidationResult ValidateSearchConstraints(SqlValue,
- FilterOp) const override;
+ RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
- RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
- Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
+ RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
- void StableSort(uint32_t*, uint32_t) const override;
+ Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
- void Sort(uint32_t*, uint32_t) const override;
+ void StableSort(uint32_t*, uint32_t) const override;
- void Serialize(StorageProto*) const override;
+ void Sort(uint32_t*, uint32_t) const override;
- uint32_t size() const override;
+ void Serialize(StorageProto*) const override;
- std::string DebugString() const override { return "DummyStorage"; }
+ uint32_t size() const override;
+
+ std::string DebugString() const override { return "DummyStorage"; }
+ };
};
} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/fake_storage.cc b/src/trace_processor/db/column/fake_storage.cc
index f130f9f..f868157 100644
--- a/src/trace_processor/db/column/fake_storage.cc
+++ b/src/trace_processor/db/column/fake_storage.cc
@@ -15,24 +15,47 @@
*/
#include "src/trace_processor/db/column/fake_storage.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <memory>
+#include <utility>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/containers/row_map.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+namespace perfetto::trace_processor::column {
FakeStorage::FakeStorage(uint32_t size, SearchStrategy strategy)
: size_(size), strategy_(strategy) {}
-SearchValidationResult FakeStorage::ValidateSearchConstraints(SqlValue,
- FilterOp) const {
+std::unique_ptr<DataNode::Queryable> FakeStorage::MakeQueryable() {
+ return std::make_unique<Queryable>(size_, strategy_, range_,
+ bit_vector_.Copy());
+}
+
+FakeStorage::Queryable::Queryable(uint32_t size,
+ SearchStrategy strategy,
+ Range range,
+ BitVector bv)
+ : size_(size),
+ strategy_(strategy),
+ range_(range),
+ bit_vector_(std::move(bv)) {}
+
+SearchValidationResult FakeStorage::Queryable::ValidateSearchConstraints(
+ SqlValue,
+ FilterOp) const {
return SearchValidationResult::kOk;
}
-RangeOrBitVector FakeStorage::Search(FilterOp, SqlValue, Range in) const {
+RangeOrBitVector FakeStorage::Queryable::Search(FilterOp,
+ SqlValue,
+ Range in) const {
switch (strategy_) {
case kAll:
return RangeOrBitVector(in);
@@ -47,9 +70,9 @@
PERFETTO_FATAL("For GCC");
}
-RangeOrBitVector FakeStorage::IndexSearch(FilterOp,
- SqlValue,
- Indices indices) const {
+RangeOrBitVector FakeStorage::Queryable::IndexSearch(FilterOp,
+ SqlValue,
+ Indices indices) const {
switch (strategy_) {
case kAll:
return RangeOrBitVector(Range(0, indices.size));
@@ -70,15 +93,15 @@
PERFETTO_FATAL("For GCC");
}
-Range FakeStorage::OrderedIndexSearch(FilterOp,
- SqlValue,
- Indices indices) const {
+Range FakeStorage::Queryable::OrderedIndexSearch(FilterOp,
+ SqlValue,
+ Indices indices) const {
if (strategy_ == kAll) {
- return Range(0, indices.size);
+ return {0, indices.size};
}
if (strategy_ == kNone) {
- return Range();
+ return {};
}
if (strategy_ == kRange) {
@@ -89,10 +112,9 @@
const uint32_t* first_outside_range =
std::partition_point(first_in_range, indices.data + indices.size,
[this](uint32_t i) { return range_.Contains(i); });
- return Range(
- static_cast<uint32_t>(std::distance(indices.data, first_in_range)),
- static_cast<uint32_t>(
- std::distance(indices.data, first_outside_range)));
+ return {static_cast<uint32_t>(std::distance(indices.data, first_in_range)),
+ static_cast<uint32_t>(
+ std::distance(indices.data, first_outside_range))};
}
PERFETTO_DCHECK(strategy_ == kBitVector);
@@ -103,26 +125,23 @@
const uint32_t* first_non_set =
std::partition_point(first_set, indices.data + indices.size,
[this](uint32_t i) { return bit_vector_.IsSet(i); });
- return Range(
- static_cast<uint32_t>(std::distance(indices.data, first_set)),
- static_cast<uint32_t>(std::distance(indices.data, first_non_set)));
+ return {static_cast<uint32_t>(std::distance(indices.data, first_set)),
+ static_cast<uint32_t>(std::distance(indices.data, first_non_set))};
}
-void FakeStorage::StableSort(uint32_t*, uint32_t) const {
+void FakeStorage::Queryable::StableSort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_FATAL("Not implemented");
}
-void FakeStorage::Sort(uint32_t*, uint32_t) const {
+void FakeStorage::Queryable::Sort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_FATAL("Not implemented");
}
-void FakeStorage::Serialize(StorageProto*) const {
+void FakeStorage::Queryable::Serialize(StorageProto*) const {
// FakeStorage doesn't really make sense to serialize.
PERFETTO_FATAL("Not implemented");
}
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/fake_storage.h b/src/trace_processor/db/column/fake_storage.h
index a1d7c6f..b4dbdde 100644
--- a/src/trace_processor/db/column/fake_storage.h
+++ b/src/trace_processor/db/column/fake_storage.h
@@ -21,59 +21,47 @@
#include <memory>
#include <string>
#include <utility>
+#include <vector>
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+namespace perfetto::trace_processor::column {
// Fake implementation of Storage for use in tests.
-class FakeStorage final : public Column {
+class FakeStorage final : public DataNode {
public:
- SearchValidationResult ValidateSearchConstraints(SqlValue,
- FilterOp) const override;
+ std::unique_ptr<Queryable> MakeQueryable() override;
- RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
-
- RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
-
- Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
-
- void StableSort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Sort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Serialize(StorageProto*) const override;
-
- static std::unique_ptr<Column> SearchAll(uint32_t size) {
- return std::unique_ptr<Column>(new FakeStorage(size, SearchStrategy::kAll));
+ static std::unique_ptr<DataNode> SearchAll(uint32_t size) {
+ return std::unique_ptr<DataNode>(
+ new FakeStorage(size, SearchStrategy::kAll));
}
- static std::unique_ptr<Column> SearchNone(uint32_t size) {
- return std::unique_ptr<Column>(
+ static std::unique_ptr<DataNode> SearchNone(uint32_t size) {
+ return std::unique_ptr<DataNode>(
new FakeStorage(size, SearchStrategy::kNone));
}
- static std::unique_ptr<Column> SearchSubset(uint32_t size, Range r) {
+ static std::unique_ptr<DataNode> SearchSubset(uint32_t size, Range r) {
std::unique_ptr<FakeStorage> storage(
new FakeStorage(size, SearchStrategy::kRange));
storage->range_ = r;
return std::move(storage);
}
- static std::unique_ptr<Column> SearchSubset(uint32_t size, BitVector bv) {
+ static std::unique_ptr<DataNode> SearchSubset(uint32_t size, BitVector bv) {
std::unique_ptr<FakeStorage> storage(
new FakeStorage(size, SearchStrategy::kBitVector));
storage->bit_vector_ = std::move(bv);
return std::move(storage);
}
- static std::unique_ptr<Column> SearchSubset(uint32_t size,
- std::vector<uint32_t> index_vec) {
+ static std::unique_ptr<DataNode> SearchSubset(
+ uint32_t size,
+ const std::vector<uint32_t>& index_vec) {
std::unique_ptr<FakeStorage> storage(
new FakeStorage(size, SearchStrategy::kBitVector));
BitVector bv(size);
@@ -84,12 +72,39 @@
return std::move(storage);
}
- uint32_t size() const override { return size_; }
-
- std::string DebugString() const override { return "FakeStorage"; }
-
private:
enum SearchStrategy { kNone, kAll, kRange, kBitVector };
+
+ class Queryable : public DataNode::Queryable {
+ public:
+ Queryable(uint32_t, SearchStrategy, Range, BitVector);
+
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
+ RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
+
+ RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Sort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ uint32_t size() const override { return size_; }
+
+ std::string DebugString() const override { return "FakeStorage"; }
+
+ private:
+ uint32_t size_ = 0;
+ SearchStrategy strategy_ = SearchStrategy::kNone;
+ Range range_;
+ BitVector bit_vector_;
+ };
+
FakeStorage(uint32_t size, SearchStrategy strategy);
uint32_t size_ = 0;
@@ -98,8 +113,6 @@
BitVector bit_vector_;
};
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
#endif // SRC_TRACE_PROCESSOR_DB_COLUMN_FAKE_STORAGE_H_
diff --git a/src/trace_processor/db/column/id_storage.cc b/src/trace_processor/db/column/id_storage.cc
index 7dc60ba..b1a7d08 100644
--- a/src/trace_processor/db/column/id_storage.cc
+++ b/src/trace_processor/db/column/id_storage.cc
@@ -15,22 +15,29 @@
*/
#include "src/trace_processor/db/column/id_storage.h"
+
#include <algorithm>
-#include <optional>
+#include <cstdint>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <string>
+#include <utility>
#include "perfetto/base/logging.h"
#include "perfetto/public/compiler.h"
#include "perfetto/trace_processor/basic_types.h"
-#include "protos/perfetto/trace_processor/serialization.pbzero.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/containers/row_map.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/column/utils.h"
#include "src/trace_processor/tp_metatrace.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+#include "protos/perfetto/trace_processor/metatrace_categories.pbzero.h"
+#include "protos/perfetto/trace_processor/serialization.pbzero.h"
+
+namespace perfetto::trace_processor::column {
namespace {
@@ -73,8 +80,9 @@
} // namespace
-SearchValidationResult IdStorage::ValidateSearchConstraints(SqlValue val,
- FilterOp op) const {
+SearchValidationResult IdStorage::Queryable::ValidateSearchConstraints(
+ SqlValue val,
+ FilterOp op) const {
// NULL checks.
if (PERFETTO_UNLIKELY(val.is_null())) {
if (op == FilterOp::kIsNotNull) {
@@ -124,9 +132,9 @@
}
// Bounds of the value.
- double_t num_val = val.type == SqlValue::kLong
- ? static_cast<double_t>(val.AsLong())
- : val.AsDouble();
+ double num_val = val.type == SqlValue::kLong
+ ? static_cast<double>(val.AsLong())
+ : val.AsDouble();
if (PERFETTO_UNLIKELY(num_val > std::numeric_limits<uint32_t>::max())) {
if (op == FilterOp::kLe || op == FilterOp::kLt || op == FilterOp::kNe) {
@@ -144,10 +152,18 @@
return SearchValidationResult::kOk;
}
-RangeOrBitVector IdStorage::Search(FilterOp op,
- SqlValue sql_val,
- Range search_range) const {
- PERFETTO_TP_TRACE(metatrace::Category::DB, "IdStorage::Search",
+IdStorage::IdStorage(uint32_t size) : size_(size) {}
+
+std::unique_ptr<DataNode::Queryable> IdStorage::MakeQueryable() {
+ return std::make_unique<Queryable>(size_);
+}
+
+IdStorage::Queryable::Queryable(uint32_t size) : size_(size) {}
+
+RangeOrBitVector IdStorage::Queryable::Search(FilterOp op,
+ SqlValue sql_val,
+ Range search_range) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB, "IdStorage::Queryable::Search",
[&search_range, op](metatrace::Record* r) {
r->AddArg("Start", std::to_string(search_range.start));
r->AddArg("End", std::to_string(search_range.end));
@@ -170,8 +186,7 @@
}
}
- uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
-
+ auto val = static_cast<uint32_t>(sql_val.AsLong());
if (op == FilterOp::kNe) {
BitVector ret(search_range.start, false);
ret.Resize(search_range.end, true);
@@ -182,15 +197,15 @@
return RangeOrBitVector(BinarySearchIntrinsic(op, val, search_range));
}
-RangeOrBitVector IdStorage::IndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
- PERFETTO_TP_TRACE(metatrace::Category::DB, "IdStorage::IndexSearch",
- [indices, op](metatrace::Record* r) {
- r->AddArg("Count", std::to_string(indices.size));
- r->AddArg("Op",
- std::to_string(static_cast<uint32_t>(op)));
- });
+RangeOrBitVector IdStorage::Queryable::IndexSearch(FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
+ PERFETTO_TP_TRACE(
+ metatrace::Category::DB, "IdStorage::Queryable::IndexSearch",
+ [indices, op](metatrace::Record* r) {
+ r->AddArg("Count", std::to_string(indices.size));
+ r->AddArg("Op", std::to_string(static_cast<uint32_t>(op)));
+ });
// It's a valid filter operation if |sql_val| is a double, although it
// requires special logic.
@@ -205,27 +220,26 @@
}
}
- uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
-
+ auto val = static_cast<uint32_t>(sql_val.AsLong());
switch (op) {
case FilterOp::kEq:
return IndexSearchWithComparator(val, indices.data, indices.size,
- std::equal_to<uint32_t>());
+ std::equal_to<>());
case FilterOp::kNe:
return IndexSearchWithComparator(val, indices.data, indices.size,
- std::not_equal_to<uint32_t>());
+ std::not_equal_to<>());
case FilterOp::kLe:
return IndexSearchWithComparator(val, indices.data, indices.size,
- std::less_equal<uint32_t>());
+ std::less_equal<>());
case FilterOp::kLt:
return IndexSearchWithComparator(val, indices.data, indices.size,
- std::less<uint32_t>());
+ std::less<>());
case FilterOp::kGt:
return IndexSearchWithComparator(val, indices.data, indices.size,
- std::greater<uint32_t>());
+ std::greater<>());
case FilterOp::kGe:
return IndexSearchWithComparator(val, indices.data, indices.size,
- std::greater_equal<uint32_t>());
+ std::greater_equal<>());
case FilterOp::kIsNotNull:
case FilterOp::kIsNull:
case FilterOp::kGlob:
@@ -235,17 +249,17 @@
PERFETTO_FATAL("FilterOp not matched");
}
-Range IdStorage::OrderedIndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+Range IdStorage::Queryable::OrderedIndexSearch(FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
PERFETTO_DCHECK(op != FilterOp::kNe);
- PERFETTO_TP_TRACE(metatrace::Category::DB, "IdStorage::OrderedIndexSearch",
- [indices, op](metatrace::Record* r) {
- r->AddArg("Count", std::to_string(indices.size));
- r->AddArg("Op",
- std::to_string(static_cast<uint32_t>(op)));
- });
+ PERFETTO_TP_TRACE(
+ metatrace::Category::DB, "IdStorage::Queryable::OrderedIndexSearch",
+ [indices, op](metatrace::Record* r) {
+ r->AddArg("Count", std::to_string(indices.size));
+ r->AddArg("Op", std::to_string(static_cast<uint32_t>(op)));
+ });
// It's a valid filter operation if |sql_val| is a double, although it
// requires special logic.
@@ -254,42 +268,42 @@
case SearchValidationResult::kOk:
break;
case SearchValidationResult::kAllData:
- return Range(0, indices.size);
+ return {0, indices.size};
case SearchValidationResult::kNoData:
- return Range();
+ return {};
}
}
- uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
+ auto val = static_cast<uint32_t>(sql_val.AsLong());
// Indices are monotonic non contiguous values if OrderedIndexSearch was
// called.
-
// Look for the first and last index and find the result of looking for this
// range in IdStorage.
Range indices_range(indices.data[0], indices.data[indices.size - 1] + 1);
Range bin_search_ret = BinarySearchIntrinsic(op, val, indices_range);
- auto start_ptr = std::lower_bound(indices.data, indices.data + indices.size,
- bin_search_ret.start);
- auto end_ptr = std::lower_bound(start_ptr, indices.data + indices.size,
- bin_search_ret.end);
-
- return Range(static_cast<uint32_t>(std::distance(indices.data, start_ptr)),
- static_cast<uint32_t>(std::distance(indices.data, end_ptr)));
+ const auto* start_ptr = std::lower_bound(
+ indices.data, indices.data + indices.size, bin_search_ret.start);
+ const auto* end_ptr = std::lower_bound(start_ptr, indices.data + indices.size,
+ bin_search_ret.end);
+ return {static_cast<uint32_t>(std::distance(indices.data, start_ptr)),
+ static_cast<uint32_t>(std::distance(indices.data, end_ptr))};
}
-Range IdStorage::BinarySearchIntrinsic(FilterOp op, Id val, Range range) const {
+Range IdStorage::Queryable::BinarySearchIntrinsic(FilterOp op,
+ Id val,
+ Range range) {
switch (op) {
case FilterOp::kEq:
- return Range(val, val + (range.start <= val && val < range.end));
+ return {val, val + (range.start <= val && val < range.end)};
case FilterOp::kLe:
- return Range(range.start, std::min(val + 1, range.end));
+ return {range.start, std::min(val + 1, range.end)};
case FilterOp::kLt:
- return Range(range.start, std::min(val, range.end));
+ return {range.start, std::min(val, range.end)};
case FilterOp::kGe:
- return Range(std::max(val, range.start), range.end);
+ return {std::max(val, range.start), range.end};
case FilterOp::kGt:
- return Range(std::max(val + 1, range.start), range.end);
+ return {std::max(val + 1, range.start), range.end};
case FilterOp::kIsNotNull:
case FilterOp::kNe:
case FilterOp::kIsNull:
@@ -300,20 +314,20 @@
PERFETTO_FATAL("FilterOp not matched");
}
-void IdStorage::StableSort(uint32_t* indices, uint32_t indices_size) const {
+void IdStorage::Queryable::StableSort(uint32_t* indices,
+ uint32_t indices_size) const {
// We can use sort, as |indices| will not have duplicates.
Sort(indices, indices_size);
}
-void IdStorage::Sort(uint32_t* indices, uint32_t indices_size) const {
+void IdStorage::Queryable::Sort(uint32_t* indices,
+ uint32_t indices_size) const {
std::sort(indices, indices + indices_size);
}
-void IdStorage::Serialize(StorageProto* storage) const {
+void IdStorage::Queryable::Serialize(StorageProto* storage) const {
auto* id_storage = storage->set_id_storage();
id_storage->set_size(size_);
}
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/id_storage.h b/src/trace_processor/db/column/id_storage.h
index e8304f5..61769dd 100644
--- a/src/trace_processor/db/column/id_storage.h
+++ b/src/trace_processor/db/column/id_storage.h
@@ -17,44 +17,55 @@
#define SRC_TRACE_PROCESSOR_DB_COLUMN_ID_STORAGE_H_
#include <cstdint>
+#include <memory>
#include <string>
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
namespace perfetto::trace_processor::column {
// Storage for Id columns.
-class IdStorage final : public Column {
+class IdStorage final : public DataNode {
public:
- explicit IdStorage(uint32_t size) : size_(size) {}
+ explicit IdStorage(uint32_t size);
- SearchValidationResult ValidateSearchConstraints(SqlValue,
- FilterOp) const override;
-
- RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
-
- RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
-
- Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
-
- void StableSort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Sort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Serialize(StorageProto*) const override;
-
- uint32_t size() const override { return size_; }
-
- std::string DebugString() const override { return "IdStorage"; }
+ std::unique_ptr<DataNode::Queryable> MakeQueryable() override;
private:
- using Id = uint32_t;
+ class Queryable : public DataNode::Queryable {
+ public:
+ explicit Queryable(uint32_t size);
- BitVector IndexSearch(FilterOp, Id, uint32_t*, uint32_t) const;
- Range BinarySearchIntrinsic(FilterOp op, Id, Range search_range) const;
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
+ RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
+
+ RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ void StableSort(uint32_t*, uint32_t) const override;
+
+ void Sort(uint32_t*, uint32_t) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ uint32_t size() const override { return size_; }
+
+ std::string DebugString() const override { return "IdStorage"; }
+
+ private:
+ using Id = uint32_t;
+
+ BitVector IndexSearch(FilterOp, Id, uint32_t*, uint32_t) const;
+ static Range BinarySearchIntrinsic(FilterOp, Id, Range);
+
+ const uint32_t size_ = 0;
+ };
const uint32_t size_ = 0;
};
diff --git a/src/trace_processor/db/column/id_storage_unittest.cc b/src/trace_processor/db/column/id_storage_unittest.cc
index 7cffe47..5d17187 100644
--- a/src/trace_processor/db/column/id_storage_unittest.cc
+++ b/src/trace_processor/db/column/id_storage_unittest.cc
@@ -14,10 +14,13 @@
* limitations under the License.
*/
#include "src/trace_processor/db/column/id_storage.h"
+#include <cstdint>
#include <limits>
+#include <vector>
#include "perfetto/trace_processor/basic_types.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/column/utils.h"
#include "test/gtest_and_gmock.h"
@@ -41,68 +44,72 @@
TEST(IdStorage, InvalidSearchConstraints) {
IdStorage storage(100);
+ auto queryable = storage.MakeQueryable();
// NULL checks
- ASSERT_EQ(storage.ValidateSearchConstraints(SqlValue(), FilterOp::kIsNull),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(SqlValue(), FilterOp::kIsNull),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(SqlValue(), FilterOp::kIsNotNull),
- SearchValidationResult::kAllData);
+ ASSERT_EQ(
+ queryable->ValidateSearchConstraints(SqlValue(), FilterOp::kIsNotNull),
+ SearchValidationResult::kAllData);
// FilterOp checks
ASSERT_EQ(
- storage.ValidateSearchConstraints(SqlValue::Long(15), FilterOp::kGlob),
+ queryable->ValidateSearchConstraints(SqlValue::Long(15), FilterOp::kGlob),
SearchValidationResult::kNoData);
- ASSERT_EQ(
- storage.ValidateSearchConstraints(SqlValue::Long(15), FilterOp::kRegex),
- SearchValidationResult::kNoData);
+ ASSERT_EQ(queryable->ValidateSearchConstraints(SqlValue::Long(15),
+ FilterOp::kRegex),
+ SearchValidationResult::kNoData);
// Type checks
- ASSERT_EQ(storage.ValidateSearchConstraints(SqlValue::String("cheese"),
- FilterOp::kGe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(SqlValue::String("cheese"),
+ FilterOp::kGe),
SearchValidationResult::kNoData);
// With double
ASSERT_EQ(
- storage.ValidateSearchConstraints(SqlValue::Double(-1), FilterOp::kGe),
+ queryable->ValidateSearchConstraints(SqlValue::Double(-1), FilterOp::kGe),
SearchValidationResult::kAllData);
// Value bounds
SqlValue max_val = SqlValue::Long(
static_cast<int64_t>(std::numeric_limits<uint32_t>::max()) + 10);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kGe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kGe),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kGt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kGt),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kEq),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kEq),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kLe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kLe),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kLt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kLt),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kNe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kNe),
SearchValidationResult::kAllData);
SqlValue min_val = SqlValue::Long(-1);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kGe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kGe),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kGt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kGt),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kNe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kNe),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kLe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kLe),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kLt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kLt),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kEq),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kEq),
SearchValidationResult::kNoData);
}
TEST(IdStorage, SearchEqSimple) {
IdStorage storage(100);
- Range range = storage.Search(FilterOp::kEq, SqlValue::Long(15), Range(10, 20))
- .TakeIfRange();
+ auto queryable = storage.MakeQueryable();
+ Range range =
+ queryable->Search(FilterOp::kEq, SqlValue::Long(15), Range(10, 20))
+ .TakeIfRange();
ASSERT_EQ(range.size(), 1u);
ASSERT_EQ(range.start, 15u);
ASSERT_EQ(range.end, 16u);
@@ -110,196 +117,213 @@
TEST(IdStorage, SearchEqOnRangeBoundary) {
IdStorage storage(100);
- Range range = storage.Search(FilterOp::kEq, SqlValue::Long(20), Range(10, 20))
- .TakeIfRange();
+ auto queryable = storage.MakeQueryable();
+ Range range =
+ queryable->Search(FilterOp::kEq, SqlValue::Long(20), Range(10, 20))
+ .TakeIfRange();
ASSERT_EQ(range.size(), 0u);
}
TEST(IdStorage, SearchEqOutsideRange) {
IdStorage storage(100);
- Range range = storage.Search(FilterOp::kEq, SqlValue::Long(25), Range(10, 20))
- .TakeIfRange();
+ auto queryable = storage.MakeQueryable();
+ Range range =
+ queryable->Search(FilterOp::kEq, SqlValue::Long(25), Range(10, 20))
+ .TakeIfRange();
ASSERT_EQ(range.size(), 0u);
}
TEST(IdStorage, SearchEqTooBig) {
IdStorage storage(100);
+ auto queryable = storage.MakeQueryable();
Range range =
- storage.Search(FilterOp::kEq, SqlValue::Long(125), Range(10, 20))
+ queryable->Search(FilterOp::kEq, SqlValue::Long(125), Range(10, 20))
.TakeIfRange();
ASSERT_EQ(range.size(), 0u);
}
TEST(IdStorage, SearchSimple) {
IdStorage storage(10);
+ auto queryable = storage.MakeQueryable();
SqlValue val = SqlValue::Long(5);
Range filter_range(3, 7);
FilterOp op = FilterOp::kEq;
- auto res = storage.Search(op, val, filter_range);
+ auto res = queryable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(5));
op = FilterOp::kNe;
- res = storage.Search(op, val, filter_range);
+ res = queryable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 6));
op = FilterOp::kLe;
- res = storage.Search(op, val, filter_range);
+ res = queryable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 5));
op = FilterOp::kLt;
- res = storage.Search(op, val, filter_range);
+ res = queryable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
op = FilterOp::kGe;
- res = storage.Search(op, val, filter_range);
+ res = queryable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(5, 6));
op = FilterOp::kGt;
- res = storage.Search(op, val, filter_range);
+ res = queryable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(6));
}
TEST(IdStorage, IndexSearchSimple) {
IdStorage storage(10);
+ auto queryable = storage.MakeQueryable();
SqlValue val = SqlValue::Long(5);
std::vector<uint32_t> indices_vec{5, 4, 3, 9, 8, 7};
Indices indices{indices_vec.data(), 6, Indices::State::kNonmonotonic};
FilterOp op = FilterOp::kEq;
- auto res = storage.IndexSearch(op, val, indices);
+ auto res = queryable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0));
op = FilterOp::kNe;
- res = storage.IndexSearch(op, val, indices);
+ res = queryable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3, 4, 5));
op = FilterOp::kLe;
- res = storage.IndexSearch(op, val, indices);
+ res = queryable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
op = FilterOp::kLt;
- res = storage.IndexSearch(op, val, indices);
+ res = queryable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2));
op = FilterOp::kGe;
- res = storage.IndexSearch(op, val, indices);
+ res = queryable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 3, 4, 5));
op = FilterOp::kGt;
- res = storage.IndexSearch(op, val, indices);
+ res = queryable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 5));
}
TEST(IdStorage, OrderedIndexSearch) {
IdStorage storage(10);
+ auto queryable = storage.MakeQueryable();
std::vector<uint32_t> indices_vec{0, 1, 2, 4, 4};
Indices indices{indices_vec.data(), 5, Indices::State::kMonotonic};
Range range =
- storage.OrderedIndexSearch(FilterOp::kEq, SqlValue::Long(2), indices);
+ queryable->OrderedIndexSearch(FilterOp::kEq, SqlValue::Long(2), indices);
ASSERT_EQ(range.start, 2u);
ASSERT_EQ(range.end, 3u);
- range = storage.OrderedIndexSearch(FilterOp::kGt, SqlValue::Long(2), indices);
+ range =
+ queryable->OrderedIndexSearch(FilterOp::kGt, SqlValue::Long(2), indices);
ASSERT_EQ(range.start, 3u);
ASSERT_EQ(range.end, 5u);
- range = storage.OrderedIndexSearch(FilterOp::kGe, SqlValue::Long(2), indices);
+ range =
+ queryable->OrderedIndexSearch(FilterOp::kGe, SqlValue::Long(2), indices);
ASSERT_EQ(range.start, 2u);
ASSERT_EQ(range.end, 5u);
- range = storage.OrderedIndexSearch(FilterOp::kLt, SqlValue::Long(2), indices);
+ range =
+ queryable->OrderedIndexSearch(FilterOp::kLt, SqlValue::Long(2), indices);
ASSERT_EQ(range.start, 0u);
ASSERT_EQ(range.end, 2u);
- range = storage.OrderedIndexSearch(FilterOp::kLe, SqlValue::Long(2), indices);
+ range =
+ queryable->OrderedIndexSearch(FilterOp::kLe, SqlValue::Long(2), indices);
ASSERT_EQ(range.start, 0u);
ASSERT_EQ(range.end, 3u);
}
TEST(IdStorage, IndexSearchEqTooBig) {
IdStorage storage(12);
+ auto queryable = storage.MakeQueryable();
std::vector<uint32_t> indices{1, 3, 5, 7, 9, 11, 2, 4};
- BitVector bv = storage
- .IndexSearch(FilterOp::kEq, SqlValue::Long(20),
- Indices{indices.data(),
- static_cast<uint32_t>(indices.size()),
- Indices::State::kMonotonic})
- .TakeIfBitVector();
+ BitVector bv =
+ queryable
+ ->IndexSearch(
+ FilterOp::kEq, SqlValue::Long(20),
+ Indices{indices.data(), static_cast<uint32_t>(indices.size()),
+ Indices::State::kMonotonic})
+ .TakeIfBitVector();
ASSERT_EQ(bv.CountSetBits(), 0u);
}
TEST(IdStorage, SearchWithIdAsDoubleSimple) {
IdStorage storage(100);
+ auto queryable = storage.MakeQueryable();
SqlValue double_val = SqlValue::Double(15.0);
SqlValue long_val = SqlValue::Long(15);
Range range(10, 20);
- auto res_double = storage.Search(FilterOp::kEq, double_val, range);
- auto res_long = storage.Search(FilterOp::kEq, long_val, range);
+ auto res_double = queryable->Search(FilterOp::kEq, double_val, range);
+ auto res_long = queryable->Search(FilterOp::kEq, long_val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(res_double),
utils::ToIndexVectorForTests(res_long));
- res_double = storage.Search(FilterOp::kNe, double_val, range);
- res_long = storage.Search(FilterOp::kNe, long_val, range);
+ res_double = queryable->Search(FilterOp::kNe, double_val, range);
+ res_long = queryable->Search(FilterOp::kNe, long_val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(res_double),
utils::ToIndexVectorForTests(res_long));
- res_double = storage.Search(FilterOp::kLe, double_val, range);
- res_long = storage.Search(FilterOp::kLe, long_val, range);
+ res_double = queryable->Search(FilterOp::kLe, double_val, range);
+ res_long = queryable->Search(FilterOp::kLe, long_val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(res_double),
utils::ToIndexVectorForTests(res_long));
- res_double = storage.Search(FilterOp::kLt, double_val, range);
- res_long = storage.Search(FilterOp::kLt, long_val, range);
+ res_double = queryable->Search(FilterOp::kLt, double_val, range);
+ res_long = queryable->Search(FilterOp::kLt, long_val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(res_double),
utils::ToIndexVectorForTests(res_long));
- res_double = storage.Search(FilterOp::kGe, double_val, range);
- res_long = storage.Search(FilterOp::kGe, long_val, range);
+ res_double = queryable->Search(FilterOp::kGe, double_val, range);
+ res_long = queryable->Search(FilterOp::kGe, long_val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(res_double),
utils::ToIndexVectorForTests(res_long));
- res_double = storage.Search(FilterOp::kGt, double_val, range);
- res_long = storage.Search(FilterOp::kGt, long_val, range);
+ res_double = queryable->Search(FilterOp::kGt, double_val, range);
+ res_long = queryable->Search(FilterOp::kGt, long_val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(res_double),
utils::ToIndexVectorForTests(res_long));
}
TEST(IdStorage, SearchWithIdAsDouble) {
IdStorage storage(100);
+ auto queryable = storage.MakeQueryable();
Range range(10, 20);
SqlValue val = SqlValue::Double(15.5);
- auto res = storage.Search(FilterOp::kEq, val, range);
+ auto res = queryable->Search(FilterOp::kEq, val, range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.Search(FilterOp::kNe, val, range);
+ res = queryable->Search(FilterOp::kNe, val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(res).size(), 20u);
- res = storage.Search(FilterOp::kLe, val, range);
+ res = queryable->Search(FilterOp::kLe, val, range);
ASSERT_THAT(utils::ToIndexVectorForTests(res),
ElementsAre(10, 11, 12, 13, 14, 15));
- res = storage.Search(FilterOp::kLt, val, range);
+ res = queryable->Search(FilterOp::kLt, val, range);
ASSERT_THAT(utils::ToIndexVectorForTests(res),
ElementsAre(10, 11, 12, 13, 14, 15));
- res = storage.Search(FilterOp::kGe, val, range);
+ res = queryable->Search(FilterOp::kGe, val, range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(16, 17, 18, 19));
- res = storage.Search(FilterOp::kGt, val, range);
+ res = queryable->Search(FilterOp::kGt, val, range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(16, 17, 18, 19));
}
TEST(IdStorage, Sort) {
std::vector<uint32_t> order{4, 3, 6, 1, 5};
IdStorage storage(10);
- storage.Sort(order.data(), 5);
+ auto queryable = storage.MakeQueryable();
+ queryable->Sort(order.data(), 5);
std::vector<uint32_t> sorted_order{1, 3, 4, 5, 6};
ASSERT_EQ(order, sorted_order);
diff --git a/src/trace_processor/db/column/null_overlay.cc b/src/trace_processor/db/column/null_overlay.cc
index 31a5794..fa93c1f 100644
--- a/src/trace_processor/db/column/null_overlay.cc
+++ b/src/trace_processor/db/column/null_overlay.cc
@@ -16,19 +16,25 @@
#include "src/trace_processor/db/column/null_overlay.h"
+#include <algorithm>
#include <cstdint>
+#include <iterator>
+#include <memory>
+#include <utility>
+#include <vector>
+#include "perfetto/base/logging.h"
+#include "perfetto/public/compiler.h"
#include "perfetto/trace_processor/basic_types.h"
-#include "protos/perfetto/trace_processor/serialization.pbzero.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/containers/row_map.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/tp_metatrace.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+#include "protos/perfetto/trace_processor/metatrace_categories.pbzero.h"
+#include "protos/perfetto/trace_processor/serialization.pbzero.h"
+
+namespace perfetto::trace_processor::column {
namespace {
BitVector ReconcileStorageResult(FilterOp op,
@@ -72,7 +78,20 @@
} // namespace
-SearchValidationResult NullOverlay::ValidateSearchConstraints(
+NullOverlay::NullOverlay(const BitVector* non_null) : non_null_(non_null) {}
+
+std::unique_ptr<DataNode::Queryable> NullOverlay::MakeQueryable(
+ std::unique_ptr<DataNode::Queryable> inner) {
+ return std::make_unique<Queryable>(std::move(inner), non_null_);
+}
+
+NullOverlay::Queryable::Queryable(std::unique_ptr<DataNode::Queryable> innner,
+ const BitVector* non_null)
+ : inner_(std::move(innner)), non_null_(non_null) {
+ PERFETTO_DCHECK(non_null_->CountSetBits() <= inner_->size());
+}
+
+SearchValidationResult NullOverlay::Queryable::ValidateSearchConstraints(
SqlValue sql_val,
FilterOp op) const {
if (op == FilterOp::kIsNull) {
@@ -82,16 +101,10 @@
return inner_->ValidateSearchConstraints(sql_val, op);
}
-NullOverlay::NullOverlay(std::unique_ptr<Column> storage,
- const BitVector* non_null)
- : inner_(std::move(storage)), non_null_(non_null) {
- PERFETTO_DCHECK(non_null_->CountSetBits() <= inner_->size());
-}
-
-RangeOrBitVector NullOverlay::Search(FilterOp op,
- SqlValue sql_val,
- Range in) const {
- PERFETTO_TP_TRACE(metatrace::Category::DB, "NullOverlay::Search");
+RangeOrBitVector NullOverlay::Queryable::Search(FilterOp op,
+ SqlValue sql_val,
+ Range in) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB, "NullOverlay::Queryable::Search");
if (op == FilterOp::kIsNull) {
switch (inner_->ValidateSearchConstraints(sql_val, op)) {
@@ -121,10 +134,11 @@
return RangeOrBitVector(std::move(res));
}
-RangeOrBitVector NullOverlay::IndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
- PERFETTO_TP_TRACE(metatrace::Category::DB, "NullOverlay::IndexSearch");
+RangeOrBitVector NullOverlay::Queryable::IndexSearch(FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB,
+ "NullOverlay::Queryable::IndexSearch");
if (op == FilterOp::kIsNull) {
switch (inner_->ValidateSearchConstraints(sql_val, op)) {
@@ -168,35 +182,36 @@
return RangeOrBitVector(std::move(res));
}
-Range NullOverlay::OrderedIndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+Range NullOverlay::Queryable::OrderedIndexSearch(FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
// For NOT EQUAL the translation or results from EQUAL needs to be done by the
// caller.
PERFETTO_CHECK(op != FilterOp::kNe);
- PERFETTO_TP_TRACE(metatrace::Category::DB, "NullOverlay::OrderedIndexSearch");
+ PERFETTO_TP_TRACE(metatrace::Category::DB,
+ "NullOverlay::Queryable::OrderedIndexSearch");
// We assume all NULLs are ordered to be in the front. We are looking for the
// first index that points to non NULL value.
const uint32_t* first_non_null =
std::partition_point(indices.data, indices.data + indices.size,
[this](uint32_t i) { return !non_null_->IsSet(i); });
- const uint32_t non_null_offset =
+ auto non_null_offset =
static_cast<uint32_t>(std::distance(indices.data, first_non_null));
- const uint32_t non_null_size = static_cast<uint32_t>(
+ auto non_null_size = static_cast<uint32_t>(
std::distance(first_non_null, indices.data + indices.size));
if (op == FilterOp::kIsNull) {
- return Range(0, non_null_offset);
+ return {0, non_null_offset};
}
if (op == FilterOp::kIsNotNull) {
switch (inner_->ValidateSearchConstraints(sql_val, op)) {
case SearchValidationResult::kNoData:
- return Range();
+ return {};
case SearchValidationResult::kAllData:
- return Range(non_null_offset, indices.size);
+ return {non_null_offset, indices.size};
case SearchValidationResult::kOk:
break;
}
@@ -211,26 +226,24 @@
Range inner_range = inner_->OrderedIndexSearch(
op, sql_val, Indices{storage_iv.data(), non_null_size, indices.state});
- return Range(inner_range.start + non_null_offset,
- inner_range.end + non_null_offset);
+ return {inner_range.start + non_null_offset,
+ inner_range.end + non_null_offset};
}
-void NullOverlay::StableSort(uint32_t*, uint32_t) const {
+void NullOverlay::Queryable::StableSort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_FATAL("Not implemented");
}
-void NullOverlay::Sort(uint32_t*, uint32_t) const {
+void NullOverlay::Queryable::Sort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_FATAL("Not implemented");
}
-void NullOverlay::Serialize(StorageProto* storage) const {
+void NullOverlay::Queryable::Serialize(StorageProto* storage) const {
auto* null_storage = storage->set_null_overlay();
non_null_->Serialize(null_storage->set_bit_vector());
inner_->Serialize(null_storage->set_storage());
}
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/null_overlay.h b/src/trace_processor/db/column/null_overlay.h
index 1bc92b7..3f0cbc7 100644
--- a/src/trace_processor/db/column/null_overlay.h
+++ b/src/trace_processor/db/column/null_overlay.h
@@ -23,38 +23,48 @@
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
namespace perfetto::trace_processor::column {
// Overlay which introduces the layer of nullability. Specifically, spreads out
// the storage with nulls using a BitVector.
-class NullOverlay : public Column {
+class NullOverlay : public DataNode {
public:
- NullOverlay(std::unique_ptr<Column>, const BitVector* non_null);
+ explicit NullOverlay(const BitVector* non_null);
- SearchValidationResult ValidateSearchConstraints(SqlValue,
- FilterOp) const override;
-
- RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
-
- RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
-
- Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
-
- void StableSort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Sort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Serialize(StorageProto*) const override;
-
- uint32_t size() const override { return non_null_->size(); }
-
- std::string DebugString() const override { return "NullOverlay"; }
+ std::unique_ptr<Queryable> MakeQueryable(std::unique_ptr<Queryable>) override;
private:
- std::unique_ptr<Column> inner_ = nullptr;
+ class Queryable : public DataNode::Queryable {
+ public:
+ Queryable(std::unique_ptr<DataNode::Queryable>, const BitVector* non_null);
+
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
+ RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
+
+ RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Sort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ uint32_t size() const override { return non_null_->size(); }
+
+ std::string DebugString() const override { return "NullOverlay"; }
+
+ private:
+ std::unique_ptr<DataNode::Queryable> inner_ = nullptr;
+ const BitVector* non_null_ = nullptr;
+ };
+
const BitVector* non_null_ = nullptr;
};
diff --git a/src/trace_processor/db/column/null_overlay_unittest.cc b/src/trace_processor/db/column/null_overlay_unittest.cc
index ea2d985..2f58068 100644
--- a/src/trace_processor/db/column/null_overlay_unittest.cc
+++ b/src/trace_processor/db/column/null_overlay_unittest.cc
@@ -16,9 +16,11 @@
#include "src/trace_processor/db/column/null_overlay.h"
+#include <cstdint>
#include <memory>
#include <vector>
+#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/containers/row_map.h"
#include "src/trace_processor/db/column/fake_storage.h"
@@ -27,9 +29,7 @@
#include "src/trace_processor/db/column/utils.h"
#include "test/gtest_and_gmock.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+namespace perfetto::trace_processor::column {
namespace {
using testing::ElementsAre;
@@ -37,111 +37,131 @@
TEST(NullOverlay, SearchInputInsideBoundary) {
BitVector bv{0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0};
- NullOverlay storage(FakeStorage::SearchAll(4u), &bv);
+ auto fake = FakeStorage::SearchAll(4u);
+ NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGt, SqlValue::Long(0), Range(1, 6));
+ auto res = queryable->Search(FilterOp::kGt, SqlValue::Long(0), Range(1, 6));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
}
TEST(NullOverlay, SearchInputOutsideBoundary) {
BitVector bv{0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0};
- NullOverlay storage(FakeStorage::SearchAll(5u), &bv);
+ auto fake = FakeStorage::SearchAll(5u);
+ NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGt, SqlValue::Long(0), Range(3, 8));
+ auto res = queryable->Search(FilterOp::kGt, SqlValue::Long(0), Range(3, 8));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 7));
}
TEST(NullOverlay, SubsetResultOutsideBoundary) {
BitVector bv{0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0};
- NullOverlay storage(FakeStorage::SearchSubset(5u, Range(1, 3)), &bv);
+ auto fake = FakeStorage::SearchSubset(5u, Range(1, 3));
+ NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 11));
+ auto res = queryable->Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 11));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
}
TEST(NullOverlay, SubsetResultOnBoundary) {
BitVector bv{0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0};
- NullOverlay storage(FakeStorage::SearchAll(5u), &bv);
+ auto fake = FakeStorage::SearchAll(5u);
+ NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 11));
+ auto res = queryable->Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 11));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 3, 4, 7, 8));
}
TEST(NullOverlay, BitVectorSubset) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay storage(FakeStorage::SearchSubset(4u, BitVector{0, 1, 0, 1}),
- &bv);
+ auto fake = FakeStorage::SearchSubset(4u, BitVector{0, 1, 0, 1});
+ NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 8));
+ auto res = queryable->Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 8));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 6));
}
TEST(NullOverlay, BitVectorSubsetIsNull) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay storage(FakeStorage::SearchSubset(4u, BitVector{0, 1, 0, 1}),
- &bv);
+ auto fake = FakeStorage::SearchSubset(4u, BitVector{0, 1, 0, 1});
+ NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kIsNull, SqlValue(), Range(0, 8));
+ auto res = queryable->Search(FilterOp::kIsNull, SqlValue(), Range(0, 8));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 2, 3, 4, 6, 7));
}
TEST(NullOverlay, IndexSearchAllElements) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay storage(FakeStorage::SearchAll(4u), &bv);
+ auto fake = FakeStorage::SearchAll(4u);
+ NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
std::vector<uint32_t> table_idx{1, 5, 2};
- auto res =
- storage.IndexSearch(FilterOp::kGt, SqlValue::Long(0),
- Indices{table_idx.data(), uint32_t(table_idx.size()),
- Indices::State::kNonmonotonic});
+ auto res = queryable->IndexSearch(
+ FilterOp::kGt, SqlValue::Long(0),
+ Indices{table_idx.data(), uint32_t(table_idx.size()),
+ Indices::State::kNonmonotonic});
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
}
TEST(NullOverlay, IndexSearchPartialElements) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay storage(FakeStorage::SearchAll(4u), &bv);
+ auto fake = FakeStorage::SearchAll(4u);
+ NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
std::vector<uint32_t> table_idx{1, 4, 2};
- auto res =
- storage.IndexSearch(FilterOp::kGt, SqlValue::Long(0),
- Indices{table_idx.data(), uint32_t(table_idx.size()),
- Indices::State::kNonmonotonic});
+ auto res = queryable->IndexSearch(
+ FilterOp::kGt, SqlValue::Long(0),
+ Indices{table_idx.data(), uint32_t(table_idx.size()),
+ Indices::State::kNonmonotonic});
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 2));
}
TEST(NullOverlay, IndexSearchIsNullOpEmptyRes) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay storage(FakeStorage::SearchNone(4u), &bv);
+ auto fake = FakeStorage::SearchNone(4u);
+ NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
std::vector<uint32_t> table_idx{0, 3, 5, 4, 2};
- auto res =
- storage.IndexSearch(FilterOp::kIsNull, SqlValue(),
- Indices{table_idx.data(), uint32_t(table_idx.size()),
- Indices::State::kNonmonotonic});
+ auto res = queryable->IndexSearch(
+ FilterOp::kIsNull, SqlValue(),
+ Indices{table_idx.data(), uint32_t(table_idx.size()),
+ Indices::State::kNonmonotonic});
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 3));
}
TEST(NullOverlay, IndexSearchIsNullOp) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay storage(FakeStorage::SearchSubset(4u, Range(2, 3)), &bv);
+ auto fake = FakeStorage::SearchSubset(4u, Range(2, 3));
+ NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
std::vector<uint32_t> table_idx{0, 3, 2, 4, 5};
- auto res =
- storage.IndexSearch(FilterOp::kIsNull, SqlValue(),
- Indices{table_idx.data(), uint32_t(table_idx.size()),
- Indices::State::kNonmonotonic});
+ auto res = queryable->IndexSearch(
+ FilterOp::kIsNull, SqlValue(),
+ Indices{table_idx.data(), uint32_t(table_idx.size()),
+ Indices::State::kNonmonotonic});
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 3, 4));
}
TEST(NullOverlay, IndexSearchIsNotNullOp) {
BitVector bv{0, 1, 1, 0, 0, 1, 1, 0};
- NullOverlay storage(FakeStorage::SearchAll(4u), &bv);
+ auto fake = FakeStorage::SearchAll(4u);
+ NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
std::vector<uint32_t> table_idx{0, 3, 4};
- auto res =
- storage.IndexSearch(FilterOp::kIsNotNull, SqlValue(),
- Indices{table_idx.data(), uint32_t(table_idx.size()),
- Indices::State::kNonmonotonic});
+ auto res = queryable->IndexSearch(
+ FilterOp::kIsNotNull, SqlValue(),
+ Indices{table_idx.data(), uint32_t(table_idx.size()),
+ Indices::State::kNonmonotonic});
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
}
@@ -149,7 +169,9 @@
BitVector bv{0, 1, 1, 1, 0, 1};
// Passing values in final storage (on normal operations)
// 0, 1, 0, 1, 0, 0
- NullOverlay storage(FakeStorage::SearchSubset(4, BitVector{1, 0, 1, 0}), &bv);
+ auto fake = FakeStorage::SearchSubset(4, BitVector{1, 0, 1, 0});
+ NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
// Passing values on final data
// NULL, NULL, 0, 1, 1
@@ -158,36 +180,40 @@
Indices::State::kNonmonotonic};
Range res =
- storage.OrderedIndexSearch(FilterOp::kIsNull, SqlValue(), indices);
+ queryable->OrderedIndexSearch(FilterOp::kIsNull, SqlValue(), indices);
ASSERT_EQ(res.start, 0u);
ASSERT_EQ(res.end, 2u);
- res = storage.OrderedIndexSearch(FilterOp::kIsNotNull, SqlValue(), indices);
+ res =
+ queryable->OrderedIndexSearch(FilterOp::kIsNotNull, SqlValue(), indices);
ASSERT_EQ(res.start, 3u);
ASSERT_EQ(res.end, 5u);
- res = storage.OrderedIndexSearch(FilterOp::kEq, SqlValue::Long(3), indices);
+ res =
+ queryable->OrderedIndexSearch(FilterOp::kEq, SqlValue::Long(3), indices);
ASSERT_EQ(res.start, 3u);
ASSERT_EQ(res.end, 5u);
- res = storage.OrderedIndexSearch(FilterOp::kGt, SqlValue::Long(3), indices);
+ res =
+ queryable->OrderedIndexSearch(FilterOp::kGt, SqlValue::Long(3), indices);
ASSERT_EQ(res.start, 3u);
ASSERT_EQ(res.end, 5u);
- res = storage.OrderedIndexSearch(FilterOp::kGe, SqlValue::Long(3), indices);
+ res =
+ queryable->OrderedIndexSearch(FilterOp::kGe, SqlValue::Long(3), indices);
ASSERT_EQ(res.start, 3u);
ASSERT_EQ(res.end, 5u);
- res = storage.OrderedIndexSearch(FilterOp::kLt, SqlValue::Long(3), indices);
+ res =
+ queryable->OrderedIndexSearch(FilterOp::kLt, SqlValue::Long(3), indices);
ASSERT_EQ(res.start, 3u);
ASSERT_EQ(res.end, 5u);
- res = storage.OrderedIndexSearch(FilterOp::kLe, SqlValue::Long(3), indices);
+ res =
+ queryable->OrderedIndexSearch(FilterOp::kLe, SqlValue::Long(3), indices);
ASSERT_EQ(res.start, 3u);
ASSERT_EQ(res.end, 5u);
}
} // namespace
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/numeric_storage.cc b/src/trace_processor/db/column/numeric_storage.cc
index 1a61977..182c1ca 100644
--- a/src/trace_processor/db/column/numeric_storage.cc
+++ b/src/trace_processor/db/column/numeric_storage.cc
@@ -22,22 +22,27 @@
#include <cstddef>
#include <cstdint>
#include <functional>
+#include <limits>
+#include <memory>
#include <string>
+#include <utility>
+#include <variant>
#include "perfetto/base/compiler.h"
#include "perfetto/base/logging.h"
#include "perfetto/public/compiler.h"
-#include "protos/perfetto/trace_processor/serialization.pbzero.h"
+#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/containers/row_map.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/column/utils.h"
#include "src/trace_processor/tp_metatrace.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+#include "protos/perfetto/trace_processor/metatrace_categories.pbzero.h"
+#include "protos/perfetto/trace_processor/serialization.pbzero.h"
+
+namespace perfetto::trace_processor::column {
namespace {
using NumericValue = std::variant<uint32_t, int32_t, int64_t, double>;
@@ -106,8 +111,9 @@
[data, search_range](auto val_data) {
using T = decltype(val_data);
const T* typed_start = static_cast<const T*>(data);
- auto lower = std::lower_bound(typed_start + search_range.start,
- typed_start + search_range.end, val_data);
+ const auto* lower =
+ std::lower_bound(typed_start + search_range.start,
+ typed_start + search_range.end, val_data);
return static_cast<uint32_t>(std::distance(typed_start, lower));
},
val);
@@ -120,8 +126,9 @@
[data, search_range](auto val_data) {
using T = decltype(val_data);
const T* typed_start = static_cast<const T*>(data);
- auto upper = std::upper_bound(typed_start + search_range.start,
- typed_start + search_range.end, val_data);
+ const auto* upper =
+ std::upper_bound(typed_start + search_range.start,
+ typed_start + search_range.end, val_data);
return static_cast<uint32_t>(std::distance(typed_start, upper));
},
val);
@@ -129,7 +136,7 @@
template <typename T>
uint32_t TypedLowerBoundExtrinsic(T val, const T* data, Indices indices) {
- auto lower = std::lower_bound(
+ const auto* lower = std::lower_bound(
indices.data, indices.data + indices.size, val,
[data](uint32_t index, T value) { return data[index] < value; });
return static_cast<uint32_t>(std::distance(indices.data, lower));
@@ -139,19 +146,19 @@
NumericValue val,
Indices indices) {
if (const auto* u32 = std::get_if<uint32_t>(&val)) {
- auto* start = static_cast<const uint32_t*>(data);
+ const auto* start = static_cast<const uint32_t*>(data);
return TypedLowerBoundExtrinsic(*u32, start, indices);
}
if (const auto* i64 = std::get_if<int64_t>(&val)) {
- auto* start = static_cast<const int64_t*>(data);
+ const auto* start = static_cast<const int64_t*>(data);
return TypedLowerBoundExtrinsic(*i64, start, indices);
}
if (const auto* i32 = std::get_if<int32_t>(&val)) {
- auto* start = static_cast<const int32_t*>(data);
+ const auto* start = static_cast<const int32_t*>(data);
return TypedLowerBoundExtrinsic(*i32, start, indices);
}
if (const auto* db = std::get_if<double>(&val)) {
- auto* start = static_cast<const double*>(data);
+ const auto* start = static_cast<const double*>(data);
return TypedLowerBoundExtrinsic(*db, start, indices);
}
PERFETTO_FATAL("Type not handled");
@@ -164,7 +171,7 @@
[data, indices](auto val_data) {
using T = decltype(val_data);
const T* typed_start = static_cast<const T*>(data);
- auto upper =
+ const auto* upper =
std::upper_bound(indices.data, indices.data + indices.size,
val_data, [typed_start](T value, uint32_t index) {
return value < typed_start[index];
@@ -210,12 +217,11 @@
double double_val = sql_val->AsDouble();
// Case when |sql_val| can be interpreted as a SqlValue::Double.
- if (std::equal_to<double>()(
- static_cast<double>(static_cast<int64_t>(double_val)), double_val)) {
+ if (std::equal_to<>()(static_cast<double>(static_cast<int64_t>(double_val)),
+ double_val)) {
*sql_val = SqlValue::Long(static_cast<int64_t>(double_val));
return SearchValidationResult::kOk;
}
-
// Logic for when the value is a real double.
switch (op) {
case FilterOp::kEq:
@@ -244,7 +250,7 @@
SearchValidationResult DoubleColumnWithInt(SqlValue* sql_val, FilterOp op) {
int64_t i = sql_val->AsLong();
- double i_as_d = static_cast<double>(i);
+ auto i_as_d = static_cast<double>(i);
// Case when |sql_val| can be interpreted as a SqlValue::Long.
if (std::equal_to<int64_t>()(i, static_cast<int64_t>(i_as_d))) {
@@ -282,7 +288,23 @@
} // namespace
-SearchValidationResult NumericStorageBase::ValidateSearchConstraints(
+NumericStorageBase::NumericStorageBase(const void* data,
+ uint32_t size,
+ ColumnType type,
+ bool is_sorted)
+ : size_(size), data_(data), storage_type_(type), is_sorted_(is_sorted) {}
+
+std::unique_ptr<DataNode::Queryable> NumericStorageBase::MakeQueryable() {
+ return std::make_unique<Queryable>(data_, size_, storage_type_, is_sorted_);
+}
+
+NumericStorageBase::Queryable::Queryable(const void* data,
+ uint32_t size,
+ ColumnType type,
+ bool is_sorted)
+ : size_(size), data_(data), storage_type_(type), is_sorted_(is_sorted) {}
+
+SearchValidationResult NumericStorageBase::Queryable::ValidateSearchConstraints(
SqlValue val,
FilterOp op) const {
// NULL checks.
@@ -391,18 +413,19 @@
PERFETTO_FATAL("For GCC");
}
-RangeOrBitVector NumericStorageBase::Search(FilterOp op,
- SqlValue sql_val,
- Range search_range) const {
+RangeOrBitVector NumericStorageBase::Queryable::Search(
+ FilterOp op,
+ SqlValue sql_val,
+ Range search_range) const {
PERFETTO_DCHECK(search_range.end <= size_);
- PERFETTO_TP_TRACE(metatrace::Category::DB, "NumericStorage::Search",
- [&search_range, op](metatrace::Record* r) {
- r->AddArg("Start", std::to_string(search_range.start));
- r->AddArg("End", std::to_string(search_range.end));
- r->AddArg("Op",
- std::to_string(static_cast<uint32_t>(op)));
- });
+ PERFETTO_TP_TRACE(
+ metatrace::Category::DB, "NumericStorage::Queryable::Search",
+ [&search_range, op](metatrace::Record* r) {
+ r->AddArg("Start", std::to_string(search_range.start));
+ r->AddArg("End", std::to_string(search_range.end));
+ r->AddArg("Op", std::to_string(static_cast<uint32_t>(op)));
+ });
// Mismatched types - value is double and column is int.
if (sql_val.type == SqlValue::kDouble &&
@@ -438,22 +461,22 @@
bv.Resize(search_range.end, true);
return RangeOrBitVector(std::move(bv));
}
-
return RangeOrBitVector(LinearSearchInternal(op, val, search_range));
}
-RangeOrBitVector NumericStorageBase::IndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+RangeOrBitVector NumericStorageBase::Queryable::IndexSearch(
+ FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
PERFETTO_DCHECK(*std::max_element(indices.data, indices.data + indices.size) <
size_);
- PERFETTO_TP_TRACE(metatrace::Category::DB, "NumericStorage::IndexSearch",
- [indices, op](metatrace::Record* r) {
- r->AddArg("Count", std::to_string(indices.size));
- r->AddArg("Op",
- std::to_string(static_cast<uint32_t>(op)));
- });
+ PERFETTO_TP_TRACE(
+ metatrace::Category::DB, "NumericStorage::Queryable::IndexSearch",
+ [indices, op](metatrace::Record* r) {
+ r->AddArg("Count", std::to_string(indices.size));
+ r->AddArg("Op", std::to_string(static_cast<uint32_t>(op)));
+ });
// Mismatched types - value is double and column is int.
if (sql_val.type == SqlValue::kDouble &&
@@ -476,19 +499,18 @@
}
NumericValue val = GetNumericTypeVariant(storage_type_, sql_val);
-
return RangeOrBitVector(
IndexSearchInternal(op, val, indices.data, indices.size));
}
-Range NumericStorageBase::OrderedIndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+Range NumericStorageBase::Queryable::OrderedIndexSearch(FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
PERFETTO_DCHECK(*std::max_element(indices.data, indices.data + indices.size) <
size_);
PERFETTO_TP_TRACE(
- metatrace::Category::DB, "NumericStorage::OrderedIndexSearch",
+ metatrace::Category::DB, "NumericStorage::Queryable::OrderedIndexSearch",
[indices, op](metatrace::Record* r) {
r->AddArg("Count", std::to_string(indices.size));
r->AddArg("Op", std::to_string(static_cast<uint32_t>(op)));
@@ -536,16 +558,16 @@
switch (op) {
case FilterOp::kEq:
- return Range(LowerBoundExtrinsic(data_, val, indices),
- UpperBoundExtrinsic(data_, val, indices));
+ return {LowerBoundExtrinsic(data_, val, indices),
+ UpperBoundExtrinsic(data_, val, indices)};
case FilterOp::kLe:
- return Range(0, UpperBoundExtrinsic(data_, val, indices));
+ return {0, UpperBoundExtrinsic(data_, val, indices)};
case FilterOp::kLt:
- return Range(0, LowerBoundExtrinsic(data_, val, indices));
+ return {0, LowerBoundExtrinsic(data_, val, indices)};
case FilterOp::kGe:
- return Range(LowerBoundExtrinsic(data_, val, indices), indices.size);
+ return {LowerBoundExtrinsic(data_, val, indices), indices.size};
case FilterOp::kGt:
- return Range(UpperBoundExtrinsic(data_, val, indices), indices.size);
+ return {UpperBoundExtrinsic(data_, val, indices), indices.size};
case FilterOp::kNe:
case FilterOp::kIsNull:
case FilterOp::kIsNotNull:
@@ -556,21 +578,22 @@
PERFETTO_FATAL("For GCC");
}
-BitVector NumericStorageBase::LinearSearchInternal(FilterOp op,
- NumericValue val,
- Range range) const {
+BitVector NumericStorageBase::Queryable::LinearSearchInternal(
+ FilterOp op,
+ NumericValue val,
+ Range range) const {
BitVector::Builder builder(range.end, range.start);
if (const auto* u32 = std::get_if<uint32_t>(&val)) {
- auto* start = static_cast<const uint32_t*>(data_) + range.start;
+ const auto* start = static_cast<const uint32_t*>(data_) + range.start;
TypedLinearSearch(*u32, start, op, builder);
} else if (const auto* i64 = std::get_if<int64_t>(&val)) {
- auto* start = static_cast<const int64_t*>(data_) + range.start;
+ const auto* start = static_cast<const int64_t*>(data_) + range.start;
TypedLinearSearch(*i64, start, op, builder);
} else if (const auto* i32 = std::get_if<int32_t>(&val)) {
- auto* start = static_cast<const int32_t*>(data_) + range.start;
+ const auto* start = static_cast<const int32_t*>(data_) + range.start;
TypedLinearSearch(*i32, start, op, builder);
} else if (const auto* db = std::get_if<double>(&val)) {
- auto* start = static_cast<const double*>(data_) + range.start;
+ const auto* start = static_cast<const double*>(data_) + range.start;
TypedLinearSearch(*db, start, op, builder);
} else {
PERFETTO_DFATAL("Invalid");
@@ -578,7 +601,7 @@
return std::move(builder).Build();
}
-BitVector NumericStorageBase::IndexSearchInternal(
+BitVector NumericStorageBase::Queryable::IndexSearchInternal(
FilterOp op,
NumericValue val,
const uint32_t* indices,
@@ -599,37 +622,37 @@
return std::move(builder).Build();
}
-Range NumericStorageBase::BinarySearchIntrinsic(FilterOp op,
- NumericValue val,
- Range search_range) const {
+Range NumericStorageBase::Queryable::BinarySearchIntrinsic(
+ FilterOp op,
+ NumericValue val,
+ Range search_range) const {
switch (op) {
case FilterOp::kEq:
- return Range(LowerBoundIntrinsic(data_, val, search_range),
- UpperBoundIntrinsic(data_, val, search_range));
+ return {LowerBoundIntrinsic(data_, val, search_range),
+ UpperBoundIntrinsic(data_, val, search_range)};
case FilterOp::kLe: {
- return Range(search_range.start,
- UpperBoundIntrinsic(data_, val, search_range));
+ return {search_range.start,
+ UpperBoundIntrinsic(data_, val, search_range)};
}
case FilterOp::kLt:
- return Range(search_range.start,
- LowerBoundIntrinsic(data_, val, search_range));
+ return {search_range.start,
+ LowerBoundIntrinsic(data_, val, search_range)};
case FilterOp::kGe:
- return Range(LowerBoundIntrinsic(data_, val, search_range),
- search_range.end);
+ return {LowerBoundIntrinsic(data_, val, search_range), search_range.end};
case FilterOp::kGt:
- return Range(UpperBoundIntrinsic(data_, val, search_range),
- search_range.end);
+ return {UpperBoundIntrinsic(data_, val, search_range), search_range.end};
case FilterOp::kNe:
case FilterOp::kIsNull:
case FilterOp::kIsNotNull:
case FilterOp::kGlob:
case FilterOp::kRegex:
- return Range();
+ return {};
}
- return Range();
+ return {};
}
-void NumericStorageBase::StableSort(uint32_t* rows, uint32_t rows_size) const {
+void NumericStorageBase::Queryable::StableSort(uint32_t* rows,
+ uint32_t rows_size) const {
std::visit(
[this, &rows, rows_size](auto val_data) {
using T = decltype(val_data);
@@ -644,12 +667,12 @@
GetNumericTypeVariant(storage_type_, SqlValue::Long(0)));
}
-void NumericStorageBase::Sort(uint32_t*, uint32_t) const {
+void NumericStorageBase::Queryable::Sort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_ELOG("Not implemented");
}
-void NumericStorageBase::Serialize(StorageProto* msg) const {
+void NumericStorageBase::Queryable::Serialize(StorageProto* msg) const {
auto* numeric_storage_msg = msg->set_numeric_storage();
numeric_storage_msg->set_is_sorted(is_sorted_);
numeric_storage_msg->set_column_type(static_cast<uint32_t>(storage_type_));
@@ -677,6 +700,4 @@
static_cast<size_t>(type_size) * size_);
}
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/numeric_storage.h b/src/trace_processor/db/column/numeric_storage.h
index d50d97b..9f24353 100644
--- a/src/trace_processor/db/column/numeric_storage.h
+++ b/src/trace_processor/db/column/numeric_storage.h
@@ -17,60 +17,73 @@
#define SRC_TRACE_PROCESSOR_DB_COLUMN_NUMERIC_STORAGE_H_
#include <cstdint>
+#include <memory>
#include <string>
#include <variant>
#include <vector>
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
namespace perfetto::trace_processor::column {
// Storage for all numeric type data (i.e. doubles, int32, int64, uint32).
-class NumericStorageBase : public Column {
+class NumericStorageBase : public DataNode {
public:
- SearchValidationResult ValidateSearchConstraints(SqlValue,
- FilterOp) const override;
-
- RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
-
- RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
-
- void StableSort(uint32_t* rows, uint32_t rows_size) const override;
-
- Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
-
- void Sort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Serialize(StorageProto*) const override;
-
- inline uint32_t size() const override { return size_; }
-
- std::string DebugString() const override { return "NumericStorage"; }
+ std::unique_ptr<DataNode::Queryable> MakeQueryable() override;
protected:
NumericStorageBase(const void* data,
uint32_t size,
ColumnType type,
- bool is_sorted = false)
- : size_(size), data_(data), storage_type_(type), is_sorted_(is_sorted) {}
+ bool is_sorted);
private:
- // All viable numeric values for ColumnTypes.
- using NumericValue = std::variant<uint32_t, int32_t, int64_t, double>;
+ class Queryable : public DataNode::Queryable {
+ public:
+ Queryable(const void* data, uint32_t size, ColumnType type, bool is_sorted);
- BitVector LinearSearchInternal(FilterOp op, NumericValue val, Range) const;
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
- BitVector IndexSearchInternal(FilterOp op,
- NumericValue value,
- const uint32_t* indices,
- uint32_t indices_count) const;
+ RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
- Range BinarySearchIntrinsic(FilterOp op,
- NumericValue val,
- Range search_range) const;
+ RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ void StableSort(uint32_t*, uint32_t) const override;
+
+ Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ void Sort(uint32_t*, uint32_t) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ inline uint32_t size() const override { return size_; }
+
+ std::string DebugString() const override { return "NumericStorage"; }
+
+ private:
+ // All viable numeric values for ColumnTypes.
+ using NumericValue = std::variant<uint32_t, int32_t, int64_t, double>;
+
+ BitVector LinearSearchInternal(FilterOp op, NumericValue val, Range) const;
+
+ BitVector IndexSearchInternal(FilterOp op,
+ NumericValue value,
+ const uint32_t* indices,
+ uint32_t indices_count) const;
+
+ Range BinarySearchIntrinsic(FilterOp op,
+ NumericValue val,
+ Range search_range) const;
+
+ const uint32_t size_ = 0;
+ const void* data_ = nullptr;
+ const ColumnType storage_type_ = ColumnType::kDummy;
+ const bool is_sorted_ = false;
+ };
const uint32_t size_ = 0;
const void* data_ = nullptr;
diff --git a/src/trace_processor/db/column/numeric_storage_unittest.cc b/src/trace_processor/db/column/numeric_storage_unittest.cc
index 428fcf4..3d5cecd 100644
--- a/src/trace_processor/db/column/numeric_storage_unittest.cc
+++ b/src/trace_processor/db/column/numeric_storage_unittest.cc
@@ -14,9 +14,16 @@
* limitations under the License.
*/
#include "src/trace_processor/db/column/numeric_storage.h"
+
+#include <cmath>
#include <cstdint>
+#include <limits>
+#include <numeric>
+#include <tuple>
+#include <vector>
#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/containers/row_map.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/column/utils.h"
#include "src/trace_processor/db/compare.h"
@@ -39,28 +46,30 @@
std::vector<uint32_t> data_vec(128);
std::iota(data_vec.begin(), data_vec.end(), 0);
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kUint32);
+ auto queryable = storage.MakeQueryable();
Range test_range(20, 100);
Range full_range(0, 100);
Range empty_range;
// NULL checks
- ASSERT_EQ(storage.ValidateSearchConstraints(SqlValue(), FilterOp::kIsNull),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(SqlValue(), FilterOp::kIsNull),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(SqlValue(), FilterOp::kIsNotNull),
- SearchValidationResult::kAllData);
+ ASSERT_EQ(
+ queryable->ValidateSearchConstraints(SqlValue(), FilterOp::kIsNotNull),
+ SearchValidationResult::kAllData);
// FilterOp checks
ASSERT_EQ(
- storage.ValidateSearchConstraints(SqlValue::Long(15), FilterOp::kGlob),
+ queryable->ValidateSearchConstraints(SqlValue::Long(15), FilterOp::kGlob),
SearchValidationResult::kNoData);
- ASSERT_EQ(
- storage.ValidateSearchConstraints(SqlValue::Long(15), FilterOp::kRegex),
- SearchValidationResult::kNoData);
+ ASSERT_EQ(queryable->ValidateSearchConstraints(SqlValue::Long(15),
+ FilterOp::kRegex),
+ SearchValidationResult::kNoData);
// Type checks
- ASSERT_EQ(storage.ValidateSearchConstraints(SqlValue::String("cheese"),
- FilterOp::kGe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(SqlValue::String("cheese"),
+ FilterOp::kGe),
SearchValidationResult::kNoData);
}
@@ -68,37 +77,38 @@
std::vector<uint32_t> data_vec(128);
std::iota(data_vec.begin(), data_vec.end(), 0);
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kUint32);
+ auto queryable = storage.MakeQueryable();
SqlValue max_val = SqlValue::Long(
static_cast<int64_t>(std::numeric_limits<uint32_t>::max()) + 10);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kGe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kGe),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kGt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kGt),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kEq),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kEq),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kLe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kLe),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kLt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kLt),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kNe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kNe),
SearchValidationResult::kAllData);
SqlValue min_val = SqlValue::Long(
static_cast<int64_t>(std::numeric_limits<uint32_t>::min()) - 1);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kGe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kGe),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kGt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kGt),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kNe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kNe),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kLe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kLe),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kLt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kLt),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kEq),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kEq),
SearchValidationResult::kNoData);
}
@@ -106,37 +116,38 @@
std::vector<int32_t> data_vec(128);
std::iota(data_vec.begin(), data_vec.end(), 0);
NumericStorage<int32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
SqlValue max_val = SqlValue::Long(
static_cast<int64_t>(std::numeric_limits<int32_t>::max()) + 10);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kGe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kGe),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kGt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kGt),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kEq),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kEq),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kLe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kLe),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kLt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kLt),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kNe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kNe),
SearchValidationResult::kAllData);
SqlValue min_val = SqlValue::Long(
static_cast<int64_t>(std::numeric_limits<int32_t>::min()) - 1);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kGe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kGe),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kGt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kGt),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kNe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kNe),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kLe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kLe),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kLt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kLt),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kEq),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kEq),
SearchValidationResult::kNoData);
}
@@ -145,8 +156,9 @@
std::vector<uint32_t> out = {0, 1, 2, 3, 4, 5, 6, 7, 8};
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kUint32);
+ auto queryable = storage.MakeQueryable();
RowMap rm(0, 9);
- storage.StableSort(out.data(), 9);
+ queryable->StableSort(out.data(), 9);
std::vector<uint32_t> stable_out{0, 3, 6, 1, 4, 7, 2, 5, 8};
ASSERT_EQ(out, stable_out);
@@ -157,8 +169,9 @@
std::vector<uint32_t> out = {1, 7, 4, 0, 6, 3, 2, 5, 8};
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kUint32);
+ auto queryable = storage.MakeQueryable();
RowMap rm(0, 9);
- storage.StableSort(out.data(), 9);
+ queryable->StableSort(out.data(), 9);
std::vector<uint32_t> stable_out{0, 6, 3, 1, 7, 4, 2, 5, 8};
ASSERT_EQ(out, stable_out);
@@ -167,106 +180,110 @@
TEST(NumericStorage, Search) {
std::vector<int32_t> data_vec{-5, 5, -4, 4, -3, 3, 0};
NumericStorage<int32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
Range test_range(1, 5);
SqlValue val = SqlValue::Long(4);
- auto res = storage.Search(FilterOp::kEq, val, test_range);
+ auto res = queryable->Search(FilterOp::kEq, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3));
- res = storage.Search(FilterOp::kNe, val, test_range);
+ res = queryable->Search(FilterOp::kNe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 4));
- res = storage.Search(FilterOp::kLt, val, test_range);
+ res = queryable->Search(FilterOp::kLt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 4));
- res = storage.Search(FilterOp::kLe, val, test_range);
+ res = queryable->Search(FilterOp::kLe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 3, 4));
- res = storage.Search(FilterOp::kGt, val, test_range);
+ res = queryable->Search(FilterOp::kGt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
- res = storage.Search(FilterOp::kGe, val, test_range);
+ res = queryable->Search(FilterOp::kGe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 3));
}
TEST(NumericStorage, SearchCompareWithNegative) {
std::vector<int32_t> data_vec{-5, 5, -4, 4, -3, 3, 0};
NumericStorage<int32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
Range test_range(1, 5);
SqlValue val = SqlValue::Long(-3);
- auto res = storage.Search(FilterOp::kEq, val, test_range);
+ auto res = queryable->Search(FilterOp::kEq, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(4));
- res = storage.Search(FilterOp::kNe, val, test_range);
+ res = queryable->Search(FilterOp::kNe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3));
- res = storage.Search(FilterOp::kLt, val, test_range);
+ res = queryable->Search(FilterOp::kLt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2));
- res = storage.Search(FilterOp::kLe, val, test_range);
+ res = queryable->Search(FilterOp::kLe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 4));
- res = storage.Search(FilterOp::kGt, val, test_range);
+ res = queryable->Search(FilterOp::kGt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 3));
- res = storage.Search(FilterOp::kGe, val, test_range);
+ res = queryable->Search(FilterOp::kGe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 3, 4));
}
TEST(NumericStorage, IndexSearch) {
std::vector<int32_t> data_vec{-5, 5, -4, 4, -3, 3, 0};
NumericStorage<int32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
// -5, -3, -3, 3, 5, 0
std::vector<uint32_t> indices_vec{0, 4, 4, 5, 1, 6};
Indices indices{indices_vec.data(), 6, Indices::State::kMonotonic};
SqlValue val = SqlValue::Long(3);
- auto res = storage.IndexSearch(FilterOp::kEq, val, indices);
+ auto res = queryable->IndexSearch(FilterOp::kEq, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3));
- res = storage.IndexSearch(FilterOp::kNe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kNe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 4, 5));
- res = storage.IndexSearch(FilterOp::kLt, val, indices);
+ res = queryable->IndexSearch(FilterOp::kLt, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 5));
- res = storage.IndexSearch(FilterOp::kLe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kLe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 5));
- res = storage.IndexSearch(FilterOp::kGt, val, indices);
+ res = queryable->IndexSearch(FilterOp::kGt, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(4));
- res = storage.IndexSearch(FilterOp::kGe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kGe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
}
TEST(NumericStorage, IndexSearchCompareWithNegative) {
std::vector<int32_t> data_vec{-5, 5, -4, 4, -3, 3, 0};
NumericStorage<int32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
// -5, -3, -3, 3, 5, 0
std::vector<uint32_t> indices_vec{0, 4, 4, 5, 1, 6};
Indices indices{indices_vec.data(), 6, Indices::State::kMonotonic};
SqlValue val = SqlValue::Long(-3);
- auto res = storage.IndexSearch(FilterOp::kEq, val, indices);
+ auto res = queryable->IndexSearch(FilterOp::kEq, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2));
- res = storage.IndexSearch(FilterOp::kNe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kNe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 3, 4, 5));
- res = storage.IndexSearch(FilterOp::kLt, val, indices);
+ res = queryable->IndexSearch(FilterOp::kLt, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0));
- res = storage.IndexSearch(FilterOp::kLe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kLe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
- res = storage.IndexSearch(FilterOp::kGt, val, indices);
+ res = queryable->IndexSearch(FilterOp::kGt, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 5));
- res = storage.IndexSearch(FilterOp::kGe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kGe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3, 4, 5));
}
@@ -274,8 +291,9 @@
std::vector<uint32_t> data_vec(128);
std::iota(data_vec.begin(), data_vec.end(), 0);
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kUint32);
+ auto queryable = storage.MakeQueryable();
RangeOrBitVector range_or_bv =
- storage.Search(FilterOp::kGe, SqlValue::Long(100), Range(0, 128));
+ queryable->Search(FilterOp::kGe, SqlValue::Long(100), Range(0, 128));
BitVector bv = std::move(range_or_bv).TakeIfBitVector();
ASSERT_TRUE(range_or_bv.IsBitVector());
ASSERT_EQ(bv.CountSetBits(), 28u);
@@ -286,8 +304,9 @@
std::vector<uint32_t> data_vec(128);
std::iota(data_vec.begin(), data_vec.end(), 0);
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kUint32, true);
+ auto queryable = storage.MakeQueryable();
Range range =
- storage.Search(FilterOp::kGe, SqlValue::Long(100), Range(0, 128))
+ queryable->Search(FilterOp::kGe, SqlValue::Long(100), Range(0, 128))
.TakeIfRange();
ASSERT_EQ(range.size(), 28u);
ASSERT_EQ(range.start, 100u);
@@ -298,8 +317,9 @@
std::vector<uint32_t> data_vec(128);
std::iota(data_vec.begin(), data_vec.end(), 0);
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kUint32, true);
+ auto queryable = storage.MakeQueryable();
BitVector bv =
- storage.Search(FilterOp::kNe, SqlValue::Long(100), Range(0, 128))
+ queryable->Search(FilterOp::kNe, SqlValue::Long(100), Range(0, 128))
.TakeIfBitVector();
ASSERT_EQ(bv.CountSetBits(), 127u);
}
@@ -308,8 +328,9 @@
std::vector<uint32_t> data_vec(128);
std::iota(data_vec.begin(), data_vec.end(), 0);
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kUint32, true);
+ auto queryable = storage.MakeQueryable();
Range range =
- storage.Search(FilterOp::kGe, SqlValue::Long(100), Range(102, 104))
+ queryable->Search(FilterOp::kGe, SqlValue::Long(100), Range(102, 104))
.TakeIfRange();
ASSERT_EQ(range.size(), 2u);
ASSERT_EQ(range.start, 102u);
@@ -323,33 +344,34 @@
Indices::State::kNonmonotonic};
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kUint32);
+ auto queryable = storage.MakeQueryable();
- Range range = storage.OrderedIndexSearch(FilterOp::kEq, SqlValue::Long(60),
- sorted_order);
+ Range range = queryable->OrderedIndexSearch(FilterOp::kEq, SqlValue::Long(60),
+ sorted_order);
ASSERT_EQ(range.size(), 1u);
ASSERT_EQ(range.start, 6u);
ASSERT_EQ(range.end, 7u);
- range = storage.OrderedIndexSearch(FilterOp::kGt, SqlValue::Long(60),
- sorted_order);
+ range = queryable->OrderedIndexSearch(FilterOp::kGt, SqlValue::Long(60),
+ sorted_order);
ASSERT_EQ(range.size(), 3u);
ASSERT_EQ(range.start, 7u);
ASSERT_EQ(range.end, 10u);
- range = storage.OrderedIndexSearch(FilterOp::kGe, SqlValue::Long(60),
- sorted_order);
+ range = queryable->OrderedIndexSearch(FilterOp::kGe, SqlValue::Long(60),
+ sorted_order);
ASSERT_EQ(range.size(), 4u);
ASSERT_EQ(range.start, 6u);
ASSERT_EQ(range.end, 10u);
- range = storage.OrderedIndexSearch(FilterOp::kLt, SqlValue::Long(60),
- sorted_order);
+ range = queryable->OrderedIndexSearch(FilterOp::kLt, SqlValue::Long(60),
+ sorted_order);
ASSERT_EQ(range.size(), 6u);
ASSERT_EQ(range.start, 0u);
ASSERT_EQ(range.end, 6u);
- range = storage.OrderedIndexSearch(FilterOp::kLe, SqlValue::Long(60),
- sorted_order);
+ range = queryable->OrderedIndexSearch(FilterOp::kLe, SqlValue::Long(60),
+ sorted_order);
ASSERT_EQ(range.size(), 7u);
ASSERT_EQ(range.start, 0u);
ASSERT_EQ(range.end, 7u);
@@ -358,211 +380,219 @@
TEST(NumericStorage, SearchWithIntAsDouble) {
std::vector<int32_t> data_vec{-5, 5, -4, 4, -3, 3, 0};
NumericStorage<int32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
Range test_range(1, 5);
SqlValue val = SqlValue::Double(4);
- auto res = storage.Search(FilterOp::kEq, val, test_range);
+ auto res = queryable->Search(FilterOp::kEq, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3));
- res = storage.Search(FilterOp::kNe, val, test_range);
+ res = queryable->Search(FilterOp::kNe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 4));
- res = storage.Search(FilterOp::kLt, val, test_range);
+ res = queryable->Search(FilterOp::kLt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 4));
- res = storage.Search(FilterOp::kLe, val, test_range);
+ res = queryable->Search(FilterOp::kLe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 3, 4));
- res = storage.Search(FilterOp::kGt, val, test_range);
+ res = queryable->Search(FilterOp::kGt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
- res = storage.Search(FilterOp::kGe, val, test_range);
+ res = queryable->Search(FilterOp::kGe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 3));
}
TEST(NumericStorage, IndexSearchWithIntAsDouble) {
std::vector<int32_t> data_vec{-5, 5, -4, 4, -3, 3, 0};
NumericStorage<int32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
// -5, -3, -3, 3, 5, 0
std::vector<uint32_t> indices_vec{0, 4, 4, 5, 1, 6};
Indices indices{indices_vec.data(), 6, Indices::State::kMonotonic};
SqlValue val = SqlValue::Double(3);
- auto res = storage.IndexSearch(FilterOp::kEq, val, indices);
+ auto res = queryable->IndexSearch(FilterOp::kEq, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3));
- res = storage.IndexSearch(FilterOp::kNe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kNe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 4, 5));
- res = storage.IndexSearch(FilterOp::kLt, val, indices);
+ res = queryable->IndexSearch(FilterOp::kLt, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 5));
- res = storage.IndexSearch(FilterOp::kLe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kLe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 5));
- res = storage.IndexSearch(FilterOp::kGt, val, indices);
+ res = queryable->IndexSearch(FilterOp::kGt, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(4));
- res = storage.IndexSearch(FilterOp::kGe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kGe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
}
TEST(NumericStorage, SearchInt32WithDouble) {
std::vector<int32_t> data_vec{-5, 5, -4, 4, -3, 3, 0};
NumericStorage<int32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
Range test_range(1, 5);
SqlValue val = SqlValue::Double(3.5);
- auto res = storage.Search(FilterOp::kEq, val, test_range);
+ auto res = queryable->Search(FilterOp::kEq, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.Search(FilterOp::kNe, val, test_range);
+ res = queryable->Search(FilterOp::kNe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3, 4));
- res = storage.Search(FilterOp::kLt, val, test_range);
+ res = queryable->Search(FilterOp::kLt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 4));
- res = storage.Search(FilterOp::kLe, val, test_range);
+ res = queryable->Search(FilterOp::kLe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 4));
- res = storage.Search(FilterOp::kGt, val, test_range);
+ res = queryable->Search(FilterOp::kGt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 3));
- res = storage.Search(FilterOp::kGe, val, test_range);
+ res = queryable->Search(FilterOp::kGe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 3));
}
TEST(NumericStorage, SearchInt32WithNegDouble) {
std::vector<int32_t> data_vec{-5, 5, -4, 4, -3, 3, 0};
NumericStorage<int32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
Range test_range(1, 5);
SqlValue val = SqlValue::Double(-3.5);
- auto res = storage.Search(FilterOp::kEq, val, test_range);
+ auto res = queryable->Search(FilterOp::kEq, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.Search(FilterOp::kNe, val, test_range);
+ res = queryable->Search(FilterOp::kNe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3, 4));
- res = storage.Search(FilterOp::kLt, val, test_range);
+ res = queryable->Search(FilterOp::kLt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2));
- res = storage.Search(FilterOp::kLe, val, test_range);
+ res = queryable->Search(FilterOp::kLe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2));
- res = storage.Search(FilterOp::kGt, val, test_range);
+ res = queryable->Search(FilterOp::kGt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 3, 4));
- res = storage.Search(FilterOp::kGe, val, test_range);
+ res = queryable->Search(FilterOp::kGe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 3, 4));
}
TEST(NumericStorage, IndexSearchInt32WithDouble) {
std::vector<int32_t> data_vec{-5, 5, -4, 4, -3, 3, 0};
NumericStorage<int32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
// -5, -3, -3, 3, 5, 0
std::vector<uint32_t> indices_vec{0, 4, 4, 5, 1, 6};
Indices indices{indices_vec.data(), 6, Indices::State::kMonotonic};
SqlValue val = SqlValue::Double(1.5);
- auto res = storage.IndexSearch(FilterOp::kEq, val, indices);
+ auto res = queryable->IndexSearch(FilterOp::kEq, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.IndexSearch(FilterOp::kNe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kNe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 4, 5));
- res = storage.IndexSearch(FilterOp::kLt, val, indices);
+ res = queryable->IndexSearch(FilterOp::kLt, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 5));
- res = storage.IndexSearch(FilterOp::kLe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kLe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 5));
- res = storage.IndexSearch(FilterOp::kGt, val, indices);
+ res = queryable->IndexSearch(FilterOp::kGt, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
- res = storage.IndexSearch(FilterOp::kGe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kGe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4));
}
TEST(NumericStorage, IndexSearchInt32WithNegDouble) {
std::vector<int32_t> data_vec{-5, 5, -4, 4, -3, 3, 0};
NumericStorage<int32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
// -5, -3, -3, 3, 5, 0
std::vector<uint32_t> indices_vec{0, 4, 4, 5, 1, 6};
Indices indices{indices_vec.data(), 6, Indices::State::kMonotonic};
SqlValue val = SqlValue::Double(-2.5);
- auto res = storage.IndexSearch(FilterOp::kEq, val, indices);
+ auto res = queryable->IndexSearch(FilterOp::kEq, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.IndexSearch(FilterOp::kNe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kNe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 4, 5));
- res = storage.IndexSearch(FilterOp::kLt, val, indices);
+ res = queryable->IndexSearch(FilterOp::kLt, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
- res = storage.IndexSearch(FilterOp::kLe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kLe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
- res = storage.IndexSearch(FilterOp::kGt, val, indices);
+ res = queryable->IndexSearch(FilterOp::kGt, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 5));
- res = storage.IndexSearch(FilterOp::kGe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kGe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 5));
}
TEST(NumericStorage, SearchUint32WithNegDouble) {
std::vector<uint32_t> data_vec{0, 1, 2, 3, 4, 5};
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
Range test_range(1, 5);
SqlValue val = SqlValue::Double(-3.5);
- auto res = storage.Search(FilterOp::kEq, val, test_range);
+ auto res = queryable->Search(FilterOp::kEq, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.Search(FilterOp::kNe, val, test_range);
+ res = queryable->Search(FilterOp::kNe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3, 4));
- res = storage.Search(FilterOp::kLt, val, test_range);
+ res = queryable->Search(FilterOp::kLt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.Search(FilterOp::kLe, val, test_range);
+ res = queryable->Search(FilterOp::kLe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.Search(FilterOp::kGt, val, test_range);
+ res = queryable->Search(FilterOp::kGt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3, 4));
- res = storage.Search(FilterOp::kGe, val, test_range);
+ res = queryable->Search(FilterOp::kGe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3, 4));
}
TEST(NumericStorage, IndexSearchUint32WithNegDouble) {
std::vector<uint32_t> data_vec{0, 1, 2, 3, 4, 5, 6};
NumericStorage<uint32_t> storage(&data_vec, ColumnType::kInt32);
+ auto queryable = storage.MakeQueryable();
std::vector<uint32_t> indices_vec{0, 4, 4, 5, 1, 6};
Indices indices{indices_vec.data(), 6, Indices::State::kMonotonic};
SqlValue val = SqlValue::Double(-2.5);
- auto res = storage.IndexSearch(FilterOp::kEq, val, indices);
+ auto res = queryable->IndexSearch(FilterOp::kEq, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.IndexSearch(FilterOp::kNe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kNe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 4, 5));
- res = storage.IndexSearch(FilterOp::kLt, val, indices);
+ res = queryable->IndexSearch(FilterOp::kLt, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.IndexSearch(FilterOp::kLe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kLe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.IndexSearch(FilterOp::kGt, val, indices);
+ res = queryable->IndexSearch(FilterOp::kGt, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 4, 5));
- res = storage.IndexSearch(FilterOp::kGe, val, indices);
+ res = queryable->IndexSearch(FilterOp::kGe, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 3, 4, 5));
}
@@ -580,24 +610,25 @@
ASSERT_TRUE(compare::LongToDouble(not_rep_i, data_vec[1]) < 0);
NumericStorage<double> storage(&data_vec, ColumnType::kDouble);
+ auto queryable = storage.MakeQueryable();
Range test_range(0, 2);
- auto res = storage.Search(FilterOp::kEq, val, test_range);
+ auto res = queryable->Search(FilterOp::kEq, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.Search(FilterOp::kNe, val, test_range);
+ res = queryable->Search(FilterOp::kNe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1));
- res = storage.Search(FilterOp::kLt, val, test_range);
+ res = queryable->Search(FilterOp::kLt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0));
- res = storage.Search(FilterOp::kLe, val, test_range);
+ res = queryable->Search(FilterOp::kLe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0));
- res = storage.Search(FilterOp::kGt, val, test_range);
+ res = queryable->Search(FilterOp::kGt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
- res = storage.Search(FilterOp::kGe, val, test_range);
+ res = queryable->Search(FilterOp::kGe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
}
@@ -615,24 +646,25 @@
ASSERT_TRUE(compare::LongToDouble(not_rep_i, data_vec[1]) > 0);
NumericStorage<double> storage(&data_vec, ColumnType::kDouble);
+ auto queryable = storage.MakeQueryable();
Range test_range(0, 2);
- auto res = storage.Search(FilterOp::kEq, val, test_range);
+ auto res = queryable->Search(FilterOp::kEq, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
- res = storage.Search(FilterOp::kNe, val, test_range);
+ res = queryable->Search(FilterOp::kNe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1));
- res = storage.Search(FilterOp::kLt, val, test_range);
+ res = queryable->Search(FilterOp::kLt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
- res = storage.Search(FilterOp::kLe, val, test_range);
+ res = queryable->Search(FilterOp::kLe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
- res = storage.Search(FilterOp::kGt, val, test_range);
+ res = queryable->Search(FilterOp::kGt, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0));
- res = storage.Search(FilterOp::kGe, val, test_range);
+ res = queryable->Search(FilterOp::kGe, val, test_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0));
}
diff --git a/src/trace_processor/db/column/selector_overlay.cc b/src/trace_processor/db/column/selector_overlay.cc
index 011f418..68a09d6 100644
--- a/src/trace_processor/db/column/selector_overlay.cc
+++ b/src/trace_processor/db/column/selector_overlay.cc
@@ -25,7 +25,7 @@
#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/tp_metatrace.h"
@@ -34,20 +34,30 @@
namespace perfetto::trace_processor::column {
-SelectorOverlay::SelectorOverlay(std::unique_ptr<Column> inner,
- const BitVector* selector)
+SelectorOverlay::SelectorOverlay(const BitVector* selector)
+ : selector_(selector) {}
+
+std::unique_ptr<DataNode::Queryable> SelectorOverlay::MakeQueryable(
+ std::unique_ptr<DataNode::Queryable> inner) {
+ return std::make_unique<Queryable>(std::move(inner), selector_);
+}
+
+SelectorOverlay::Queryable::Queryable(
+ std::unique_ptr<DataNode::Queryable> inner,
+ const BitVector* selector)
: inner_(std::move(inner)), selector_(selector) {}
-SearchValidationResult SelectorOverlay::ValidateSearchConstraints(
+SearchValidationResult SelectorOverlay::Queryable::ValidateSearchConstraints(
SqlValue sql_val,
FilterOp op) const {
return inner_->ValidateSearchConstraints(sql_val, op);
}
-RangeOrBitVector SelectorOverlay::Search(FilterOp op,
- SqlValue sql_val,
- Range in) const {
- PERFETTO_TP_TRACE(metatrace::Category::DB, "SelectorOverlay::Search");
+RangeOrBitVector SelectorOverlay::Queryable::Search(FilterOp op,
+ SqlValue sql_val,
+ Range in) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB,
+ "SelectorOverlay::Queryable::Search");
// Figure out the bounds of the indices in the underlying storage and search
// it.
@@ -75,16 +85,18 @@
return RangeOrBitVector(std::move(res).Build());
}
-RangeOrBitVector SelectorOverlay::IndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+RangeOrBitVector SelectorOverlay::Queryable::IndexSearch(
+ FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
PERFETTO_DCHECK(
indices.size == 0 ||
*std::max_element(indices.data, indices.data + indices.size) <=
selector_->size());
// TODO(b/307482437): Use OrderedIndexSearch if arrangement orders storage.
- PERFETTO_TP_TRACE(metatrace::Category::DB, "SelectorOverlay::IndexSearch");
+ PERFETTO_TP_TRACE(metatrace::Category::DB,
+ "SelectorOverlay::Queryable::IndexSearch");
// To go from TableIndexVector to StorageIndexVector we need to find index in
// |selector_| by looking only into set bits.
@@ -98,9 +110,9 @@
indices.state});
}
-Range SelectorOverlay::OrderedIndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+Range SelectorOverlay::Queryable::OrderedIndexSearch(FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
// To go from TableIndexVector to StorageIndexVector we need to find index in
// |selector_| by looking only into set bits.
std::vector<uint32_t> inner_indices(indices.size);
@@ -113,17 +125,17 @@
indices.state});
}
-void SelectorOverlay::StableSort(uint32_t*, uint32_t) const {
+void SelectorOverlay::Queryable::StableSort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_FATAL("Not implemented");
}
-void SelectorOverlay::Sort(uint32_t*, uint32_t) const {
+void SelectorOverlay::Queryable::Sort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_FATAL("Not implemented");
}
-void SelectorOverlay::Serialize(StorageProto* storage) const {
+void SelectorOverlay::Queryable::Serialize(StorageProto* storage) const {
auto* selector_overlay = storage->set_selector_overlay();
inner_->Serialize(selector_overlay->set_storage());
selector_->Serialize(selector_overlay->set_bit_vector());
diff --git a/src/trace_processor/db/column/selector_overlay.h b/src/trace_processor/db/column/selector_overlay.h
index 33666e5..f901ba8 100644
--- a/src/trace_processor/db/column/selector_overlay.h
+++ b/src/trace_processor/db/column/selector_overlay.h
@@ -23,7 +23,7 @@
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
namespace perfetto::trace_processor::column {
@@ -31,31 +31,41 @@
// Storage which "selects" specific rows from an underlying storage using a
// BitVector. See ArrangementOverlay for a more generic class which allows
// duplication and rearragement but is less performant.
-class SelectorOverlay : public Column {
+class SelectorOverlay : public DataNode {
public:
- SelectorOverlay(std::unique_ptr<Column>, const BitVector*);
+ explicit SelectorOverlay(const BitVector*);
- SearchValidationResult ValidateSearchConstraints(SqlValue,
- FilterOp) const override;
-
- RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
-
- RangeOrBitVector IndexSearch(FilterOp p, SqlValue, Indices) const override;
-
- Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
-
- void StableSort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Sort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Serialize(StorageProto*) const override;
-
- uint32_t size() const override { return selector_->size(); }
-
- std::string DebugString() const override { return "SelectorOverlay"; }
+ std::unique_ptr<Queryable> MakeQueryable(std::unique_ptr<Queryable>) override;
private:
- std::unique_ptr<Column> inner_ = nullptr;
+ class Queryable : public DataNode::Queryable {
+ public:
+ Queryable(std::unique_ptr<DataNode::Queryable>, const BitVector*);
+
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
+ RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
+
+ RangeOrBitVector IndexSearch(FilterOp p, SqlValue, Indices) const override;
+
+ Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Sort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ uint32_t size() const override { return selector_->size(); }
+
+ std::string DebugString() const override { return "SelectorOverlay"; }
+
+ private:
+ std::unique_ptr<DataNode::Queryable> inner_ = nullptr;
+ const BitVector* selector_ = nullptr;
+ };
+
const BitVector* selector_ = nullptr;
};
diff --git a/src/trace_processor/db/column/selector_overlay_unittest.cc b/src/trace_processor/db/column/selector_overlay_unittest.cc
index 9d44010..a093f68 100644
--- a/src/trace_processor/db/column/selector_overlay_unittest.cc
+++ b/src/trace_processor/db/column/selector_overlay_unittest.cc
@@ -16,13 +16,17 @@
#include "src/trace_processor/db/column/selector_overlay.h"
+#include <cstdint>
+#include <vector>
+
+#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/db/column/fake_storage.h"
+#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/column/utils.h"
#include "test/gtest_and_gmock.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+namespace perfetto::trace_processor::column {
namespace {
using testing::ElementsAre;
@@ -30,47 +34,52 @@
TEST(SelectorOverlay, SearchAll) {
BitVector selector{0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1};
- SelectorOverlay storage(FakeStorage::SearchAll(10), &selector);
+ auto fake = FakeStorage::SearchAll(10);
+ SelectorOverlay storage(&selector);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0u), Range(1, 4));
+ auto res = queryable->Search(FilterOp::kGe, SqlValue::Long(0u), Range(1, 4));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1u, 2u, 3u));
}
TEST(SelectorOverlay, SearchNone) {
BitVector selector{0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1};
- SelectorOverlay storage(FakeStorage::SearchNone(10), &selector);
+ auto fake = FakeStorage::SearchNone(10);
+ SelectorOverlay storage(&selector);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0u), Range(1, 4));
+ auto res = queryable->Search(FilterOp::kGe, SqlValue::Long(0u), Range(1, 4));
ASSERT_THAT(utils::ToIndexVectorForTests(res), IsEmpty());
}
TEST(SelectorOverlay, SearchLimited) {
BitVector selector{0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1};
- SelectorOverlay storage(FakeStorage::SearchSubset(10, Range(4, 5)),
- &selector);
+ auto fake = FakeStorage::SearchSubset(10, Range(4, 5));
+ SelectorOverlay storage(&selector);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0u), Range(1, 5));
+ auto res = queryable->Search(FilterOp::kGe, SqlValue::Long(0u), Range(1, 5));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2u));
}
TEST(SelectorOverlay, SearchBitVector) {
BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
- SelectorOverlay storage(
- FakeStorage::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0})),
- &selector);
+ auto fake = FakeStorage::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0}));
+ SelectorOverlay storage(&selector);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
- auto res = storage.Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 4));
+ auto res = queryable->Search(FilterOp::kGe, SqlValue::Long(0u), Range(0, 4));
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 2));
}
TEST(SelectorOverlay, IndexSearch) {
BitVector selector{0, 1, 1, 0, 0, 1, 1, 0};
- SelectorOverlay storage(
- FakeStorage::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0})),
- &selector);
+ auto fake = FakeStorage::SearchSubset(8, BitVector({0, 1, 0, 1, 0, 1, 0, 0}));
+ SelectorOverlay storage(&selector);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
std::vector<uint32_t> table_idx{1u, 0u, 3u};
- RangeOrBitVector res = storage.IndexSearch(
+ RangeOrBitVector res = queryable->IndexSearch(
FilterOp::kGe, SqlValue::Long(0u),
Indices{table_idx.data(), static_cast<uint32_t>(table_idx.size()),
Indices::State::kNonmonotonic});
@@ -79,10 +88,12 @@
TEST(SelectorOverlay, OrderedIndexSearchTrivial) {
BitVector selector{1, 0, 1, 0, 1};
- SelectorOverlay storage(FakeStorage::SearchAll(5), &selector);
+ auto fake = FakeStorage::SearchAll(5);
+ SelectorOverlay storage(&selector);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
std::vector<uint32_t> table_idx{1u, 0u, 2u};
- Range res = storage.OrderedIndexSearch(
+ Range res = queryable->OrderedIndexSearch(
FilterOp::kGe, SqlValue::Long(0u),
Indices{table_idx.data(), static_cast<uint32_t>(table_idx.size()),
Indices::State::kNonmonotonic});
@@ -92,10 +103,12 @@
TEST(SelectorOverlay, OrderedIndexSearchNone) {
BitVector selector{1, 0, 1, 0, 1};
- SelectorOverlay storage(FakeStorage::SearchNone(5), &selector);
+ auto fake = FakeStorage::SearchNone(5);
+ SelectorOverlay storage(&selector);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
std::vector<uint32_t> table_idx{1u, 0u, 2u};
- Range res = storage.OrderedIndexSearch(
+ Range res = queryable->OrderedIndexSearch(
FilterOp::kGe, SqlValue::Long(0u),
Indices{table_idx.data(), static_cast<uint32_t>(table_idx.size()),
Indices::State::kNonmonotonic});
@@ -103,6 +116,4 @@
}
} // namespace
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/set_id_storage.cc b/src/trace_processor/db/column/set_id_storage.cc
index 20a9f38..75019cc 100644
--- a/src/trace_processor/db/column/set_id_storage.cc
+++ b/src/trace_processor/db/column/set_id_storage.cc
@@ -16,19 +16,29 @@
#include "src/trace_processor/db/column/set_id_storage.h"
+#include <algorithm>
+#include <cstdint>
#include <functional>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
#include "perfetto/base/logging.h"
-#include "protos/perfetto/trace_processor/serialization.pbzero.h"
+#include "perfetto/public/compiler.h"
+#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/containers/row_map.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/column/utils.h"
#include "src/trace_processor/tp_metatrace.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+#include "protos/perfetto/trace_processor/metatrace_categories.pbzero.h"
+#include "protos/perfetto/trace_processor/serialization.pbzero.h"
+
+namespace perfetto::trace_processor::column {
namespace {
@@ -38,7 +48,7 @@
if (id >= range.end) {
return range.end;
}
- auto upper =
+ const auto* upper =
std::upper_bound(data + std::max(range.start, id), data + range.end, id);
return static_cast<uint32_t>(std::distance(data, upper));
}
@@ -57,7 +67,17 @@
} // namespace
-SearchValidationResult SetIdStorage::ValidateSearchConstraints(
+SetIdStorage::SetIdStorage(const std::vector<uint32_t>* values)
+ : values_(values) {}
+
+std::unique_ptr<DataNode::Queryable> SetIdStorage::MakeQueryable() {
+ return std::make_unique<Queryable>(values_);
+}
+
+SetIdStorage::Queryable::Queryable(const std::vector<uint32_t>* values)
+ : values_(values) {}
+
+SearchValidationResult SetIdStorage::Queryable::ValidateSearchConstraints(
SqlValue val,
FilterOp op) const {
// NULL checks.
@@ -108,10 +128,9 @@
}
// Bounds of the value.
- double_t num_val = val.type == SqlValue::kLong
- ? static_cast<double_t>(val.AsLong())
- : val.AsDouble();
-
+ double num_val = val.type == SqlValue::kLong
+ ? static_cast<double>(val.AsLong())
+ : val.AsDouble();
if (PERFETTO_UNLIKELY(num_val > std::numeric_limits<uint32_t>::max())) {
if (op == FilterOp::kLe || op == FilterOp::kLt || op == FilterOp::kNe) {
return SearchValidationResult::kAllData;
@@ -128,12 +147,12 @@
return SearchValidationResult::kOk;
}
-RangeOrBitVector SetIdStorage::Search(FilterOp op,
- SqlValue sql_val,
- Range search_range) const {
+RangeOrBitVector SetIdStorage::Queryable::Search(FilterOp op,
+ SqlValue sql_val,
+ Range search_range) const {
PERFETTO_DCHECK(search_range.end <= size());
- PERFETTO_TP_TRACE(metatrace::Category::DB, "SetIdStorage::Search",
+ PERFETTO_TP_TRACE(metatrace::Category::DB, "SetIdStorage::Queryable::Search",
[&search_range, op](metatrace::Record* r) {
r->AddArg("Start", std::to_string(search_range.start));
r->AddArg("End", std::to_string(search_range.end));
@@ -154,8 +173,7 @@
}
}
- uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
-
+ auto val = static_cast<uint32_t>(sql_val.AsLong());
if (op == FilterOp::kNe) {
// Not equal is a special operation on binary search, as it doesn't define a
// range, and rather just `not` range returned with `equal` operation.
@@ -169,15 +187,15 @@
return RangeOrBitVector(BinarySearchIntrinsic(op, val, search_range));
}
-RangeOrBitVector SetIdStorage::IndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
- PERFETTO_TP_TRACE(metatrace::Category::DB, "SetIdStorage::IndexSearch",
- [indices, op](metatrace::Record* r) {
- r->AddArg("Count", std::to_string(indices.size));
- r->AddArg("Op",
- std::to_string(static_cast<uint32_t>(op)));
- });
+RangeOrBitVector SetIdStorage::Queryable::IndexSearch(FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
+ PERFETTO_TP_TRACE(
+ metatrace::Category::DB, "SetIdStorage::Queryable::IndexSearch",
+ [indices, op](metatrace::Record* r) {
+ r->AddArg("Count", std::to_string(indices.size));
+ r->AddArg("Op", std::to_string(static_cast<uint32_t>(op)));
+ });
// It's a valid filter operation if |sql_val| is a double, although it
// requires special logic.
@@ -192,8 +210,7 @@
}
}
- uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
-
+ auto val = static_cast<uint32_t>(sql_val.AsLong());
BitVector::Builder builder(indices.size);
// TODO(mayzner): Instead of utils::IndexSearchWithComparator, use the
@@ -201,27 +218,27 @@
switch (op) {
case FilterOp::kEq:
utils::IndexSearchWithComparator(val, values_->data(), indices.data,
- std::equal_to<uint32_t>(), builder);
+ std::equal_to<>(), builder);
break;
case FilterOp::kNe:
utils::IndexSearchWithComparator(val, values_->data(), indices.data,
- std::not_equal_to<uint32_t>(), builder);
+ std::not_equal_to<>(), builder);
break;
case FilterOp::kLe:
utils::IndexSearchWithComparator(val, values_->data(), indices.data,
- std::less_equal<uint32_t>(), builder);
+ std::less_equal<>(), builder);
break;
case FilterOp::kLt:
utils::IndexSearchWithComparator(val, values_->data(), indices.data,
- std::less<uint32_t>(), builder);
+ std::less<>(), builder);
break;
case FilterOp::kGt:
utils::IndexSearchWithComparator(val, values_->data(), indices.data,
- std::greater<uint32_t>(), builder);
+ std::greater<>(), builder);
break;
case FilterOp::kGe:
utils::IndexSearchWithComparator(val, values_->data(), indices.data,
- std::greater_equal<uint32_t>(), builder);
+ std::greater_equal<>(), builder);
break;
case FilterOp::kIsNotNull:
return RangeOrBitVector(Range(0, indices.size));
@@ -234,42 +251,40 @@
return RangeOrBitVector(std::move(builder).Build());
}
-Range SetIdStorage::OrderedIndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+Range SetIdStorage::Queryable::OrderedIndexSearch(FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
// Indices are monotonic non-contiguous values.
- auto res = SetIdStorage::Search(
+ auto res = SetIdStorage::Queryable::Search(
op, sql_val, Range(indices.data[0], indices.data[indices.size - 1] + 1));
PERFETTO_CHECK(res.IsRange());
Range res_range = std::move(res).TakeIfRange();
- auto start_ptr = std::lower_bound(indices.data, indices.data + indices.size,
- res_range.start);
- auto end_ptr =
+ const auto* start_ptr = std::lower_bound(
+ indices.data, indices.data + indices.size, res_range.start);
+ const auto* end_ptr =
std::lower_bound(start_ptr, indices.data + indices.size, res_range.end);
- return Range(static_cast<uint32_t>(std::distance(indices.data, start_ptr)),
- static_cast<uint32_t>(std::distance(indices.data, end_ptr)));
+ return {static_cast<uint32_t>(std::distance(indices.data, start_ptr)),
+ static_cast<uint32_t>(std::distance(indices.data, end_ptr))};
}
-Range SetIdStorage::BinarySearchIntrinsic(FilterOp op,
- SetId val,
- Range range) const {
+Range SetIdStorage::Queryable::BinarySearchIntrinsic(FilterOp op,
+ SetId val,
+ Range range) const {
switch (op) {
case FilterOp::kEq:
- return Range(LowerBoundIntrinsic(values_->data(), val, range),
- UpperBoundIntrinsic(values_->data(), val, range));
+ return {LowerBoundIntrinsic(values_->data(), val, range),
+ UpperBoundIntrinsic(values_->data(), val, range)};
case FilterOp::kLe: {
- return Range(range.start,
- UpperBoundIntrinsic(values_->data(), val, range));
+ return {range.start, UpperBoundIntrinsic(values_->data(), val, range)};
}
case FilterOp::kLt:
- return Range(range.start,
- LowerBoundIntrinsic(values_->data(), val, range));
+ return {range.start, LowerBoundIntrinsic(values_->data(), val, range)};
case FilterOp::kGe:
- return Range(LowerBoundIntrinsic(values_->data(), val, range), range.end);
+ return {LowerBoundIntrinsic(values_->data(), val, range), range.end};
case FilterOp::kGt:
- return Range(UpperBoundIntrinsic(values_->data(), val, range), range.end);
+ return {UpperBoundIntrinsic(values_->data(), val, range), range.end};
case FilterOp::kIsNotNull:
return range;
case FilterOp::kNe:
@@ -277,27 +292,25 @@
case FilterOp::kIsNull:
case FilterOp::kGlob:
case FilterOp::kRegex:
- return Range();
+ return {};
}
- return Range();
+ return {};
}
-void SetIdStorage::StableSort(uint32_t*, uint32_t) const {
+void SetIdStorage::Queryable::StableSort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_ELOG("Not implemented");
}
-void SetIdStorage::Sort(uint32_t*, uint32_t) const {
+void SetIdStorage::Queryable::Sort(uint32_t*, uint32_t) const {
// TODO(b/307482437): Implement.
PERFETTO_ELOG("Not implemented");
}
-void SetIdStorage::Serialize(StorageProto* msg) const {
+void SetIdStorage::Queryable::Serialize(StorageProto* msg) const {
auto* vec_msg = msg->set_set_id_storage();
vec_msg->set_values(reinterpret_cast<const uint8_t*>(values_->data()),
sizeof(SetId) * size());
}
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/column/set_id_storage.h b/src/trace_processor/db/column/set_id_storage.h
index 46e71a5..f7cab36 100644
--- a/src/trace_processor/db/column/set_id_storage.h
+++ b/src/trace_processor/db/column/set_id_storage.h
@@ -17,50 +17,59 @@
#define SRC_TRACE_PROCESSOR_DB_COLUMN_SET_ID_STORAGE_H_
#include <cstdint>
+#include <memory>
#include <string>
#include <vector>
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
namespace perfetto::trace_processor::column {
// Storage for SetId columns.
-class SetIdStorage final : public Column {
+class SetIdStorage final : public DataNode {
public:
using SetId = uint32_t;
- explicit SetIdStorage(const std::vector<uint32_t>* data) : values_(data) {}
+ explicit SetIdStorage(const std::vector<uint32_t>*);
- SearchValidationResult ValidateSearchConstraints(SqlValue,
- FilterOp) const override;
-
- RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
-
- RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
-
- Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
-
- void StableSort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Sort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Serialize(StorageProto*) const override;
-
- uint32_t size() const override {
- return static_cast<uint32_t>(values_->size());
- }
-
- std::string DebugString() const override { return "SetIdStorage"; }
+ std::unique_ptr<Queryable> MakeQueryable() override;
private:
- BitVector IndexSearch(FilterOp, SetId, uint32_t*, uint32_t) const;
- Range BinarySearchIntrinsic(FilterOp, SetId, Range search_range) const;
+ class Queryable : public DataNode::Queryable {
+ public:
+ explicit Queryable(const std::vector<uint32_t>*);
- // TODO(b/307482437): After the migration vectors should be owned by storage,
- // so change from pointer to value.
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
+
+ RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
+
+ RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ void StableSort(uint32_t*, uint32_t) const override;
+
+ void Sort(uint32_t*, uint32_t) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ uint32_t size() const override {
+ return static_cast<uint32_t>(values_->size());
+ }
+
+ std::string DebugString() const override { return "SetIdStorage"; }
+
+ private:
+ BitVector IndexSearch(FilterOp, SetId, uint32_t*, uint32_t) const;
+ Range BinarySearchIntrinsic(FilterOp, SetId, Range search_range) const;
+
+ const std::vector<SetId>* values_ = nullptr;
+ };
+
const std::vector<SetId>* values_ = nullptr;
};
diff --git a/src/trace_processor/db/column/set_id_storage_unittest.cc b/src/trace_processor/db/column/set_id_storage_unittest.cc
index 38b2878..a6ef367 100644
--- a/src/trace_processor/db/column/set_id_storage_unittest.cc
+++ b/src/trace_processor/db/column/set_id_storage_unittest.cc
@@ -15,13 +15,18 @@
*/
#include "src/trace_processor/db/column/set_id_storage.h"
+#include <cstdint>
+#include <limits>
+#include <tuple>
+#include <vector>
+
#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/column/utils.h"
#include "test/gtest_and_gmock.h"
-namespace perfetto {
-namespace trace_processor {
+namespace perfetto::trace_processor {
inline bool operator==(const Range& a, const Range& b) {
return std::tie(a.start, a.end) == std::tie(b.start, b.end);
@@ -40,149 +45,159 @@
TEST(SetIdStorage, InvalidSearchConstraints) {
std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
SetIdStorage storage(&storage_data);
+ auto queryable = storage.MakeQueryable();
+
// NULL checks
- ASSERT_EQ(storage.ValidateSearchConstraints(SqlValue(), FilterOp::kIsNull),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(SqlValue(), FilterOp::kIsNull),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(SqlValue(), FilterOp::kIsNotNull),
- SearchValidationResult::kAllData);
+ ASSERT_EQ(
+ queryable->ValidateSearchConstraints(SqlValue(), FilterOp::kIsNotNull),
+ SearchValidationResult::kAllData);
// FilterOp checks
ASSERT_EQ(
- storage.ValidateSearchConstraints(SqlValue::Long(15), FilterOp::kGlob),
+ queryable->ValidateSearchConstraints(SqlValue::Long(15), FilterOp::kGlob),
SearchValidationResult::kNoData);
- ASSERT_EQ(
- storage.ValidateSearchConstraints(SqlValue::Long(15), FilterOp::kRegex),
- SearchValidationResult::kNoData);
+ ASSERT_EQ(queryable->ValidateSearchConstraints(SqlValue::Long(15),
+ FilterOp::kRegex),
+ SearchValidationResult::kNoData);
// Type checks
- ASSERT_EQ(storage.ValidateSearchConstraints(SqlValue::String("cheese"),
- FilterOp::kGe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(SqlValue::String("cheese"),
+ FilterOp::kGe),
SearchValidationResult::kNoData);
// Value bounds
SqlValue max_val = SqlValue::Long(
static_cast<int64_t>(std::numeric_limits<uint32_t>::max()) + 10);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kGe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kGe),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kGt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kGt),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kEq),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kEq),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kLe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kLe),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kLt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kLt),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(max_val, FilterOp::kNe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(max_val, FilterOp::kNe),
SearchValidationResult::kAllData);
SqlValue min_val = SqlValue::Long(
static_cast<int64_t>(std::numeric_limits<uint32_t>::min()) - 1);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kGe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kGe),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kGt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kGt),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kNe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kNe),
SearchValidationResult::kAllData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kLe),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kLe),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kLt),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kLt),
SearchValidationResult::kNoData);
- ASSERT_EQ(storage.ValidateSearchConstraints(min_val, FilterOp::kEq),
+ ASSERT_EQ(queryable->ValidateSearchConstraints(min_val, FilterOp::kEq),
SearchValidationResult::kNoData);
}
TEST(SetIdStorage, SearchSimple) {
std::vector<uint32_t> storage_data{0, 0, 2, 2, 4, 4, 6, 6};
SetIdStorage storage(&storage_data);
+ auto queryable = storage.MakeQueryable();
SqlValue val = SqlValue::Long(4);
Range filter_range(1, 7);
FilterOp op = FilterOp::kEq;
- auto res = storage.Search(op, val, filter_range);
+ auto res = queryable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(4, 5));
op = FilterOp::kNe;
- res = storage.Search(op, val, filter_range);
+ res = queryable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3, 6));
op = FilterOp::kLe;
- res = storage.Search(op, val, filter_range);
+ res = queryable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3, 4, 5));
op = FilterOp::kLt;
- res = storage.Search(op, val, filter_range);
+ res = queryable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3));
op = FilterOp::kGe;
- res = storage.Search(op, val, filter_range);
+ res = queryable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(4, 5, 6));
op = FilterOp::kGt;
- res = storage.Search(op, val, filter_range);
+ res = queryable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(6));
}
TEST(SetIdStorage, IndexSearchSimple) {
std::vector<uint32_t> storage_data{0, 0, 2, 2, 4, 4, 6, 6};
SetIdStorage storage(&storage_data);
+ auto queryable = storage.MakeQueryable();
SqlValue val = SqlValue::Long(4);
// 6, 4, 2, 0
std::vector<uint32_t> indices_vec{6, 4, 2, 0};
Indices indices{indices_vec.data(), 4, Indices::State::kNonmonotonic};
FilterOp op = FilterOp::kEq;
- auto res = storage.IndexSearch(op, val, indices);
+ auto res = queryable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1));
op = FilterOp::kNe;
- res = storage.IndexSearch(op, val, indices);
+ res = queryable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 2, 3));
op = FilterOp::kLe;
- res = storage.IndexSearch(op, val, indices);
+ res = queryable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 3));
op = FilterOp::kLt;
- res = storage.IndexSearch(op, val, indices);
+ res = queryable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 3));
op = FilterOp::kGe;
- res = storage.IndexSearch(op, val, indices);
+ res = queryable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1));
op = FilterOp::kGt;
- res = storage.IndexSearch(op, val, indices);
+ res = queryable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0));
}
TEST(SetIdStorage, OrderedIndexSearchSimple) {
std::vector<uint32_t> storage_data{0, 0, 2, 2, 4, 4, 6, 6};
SetIdStorage storage(&storage_data);
+ auto queryable = storage.MakeQueryable();
// 0, 2, 2, 4
std::vector<uint32_t> indices_vec{0, 3, 3, 5};
Indices indices{indices_vec.data(), 4, Indices::State::kMonotonic};
Range range =
- storage.OrderedIndexSearch(FilterOp::kEq, SqlValue::Long(2), indices);
+ queryable->OrderedIndexSearch(FilterOp::kEq, SqlValue::Long(2), indices);
ASSERT_EQ(range.start, 1u);
ASSERT_EQ(range.end, 3u);
- range = storage.OrderedIndexSearch(FilterOp::kGt, SqlValue::Long(2), indices);
+ range =
+ queryable->OrderedIndexSearch(FilterOp::kGt, SqlValue::Long(2), indices);
ASSERT_EQ(range.start, 3u);
ASSERT_EQ(range.end, 4u);
- range = storage.OrderedIndexSearch(FilterOp::kGe, SqlValue::Long(2), indices);
+ range =
+ queryable->OrderedIndexSearch(FilterOp::kGe, SqlValue::Long(2), indices);
ASSERT_EQ(range.start, 1u);
ASSERT_EQ(range.end, 4u);
- range = storage.OrderedIndexSearch(FilterOp::kLt, SqlValue::Long(2), indices);
+ range =
+ queryable->OrderedIndexSearch(FilterOp::kLt, SqlValue::Long(2), indices);
ASSERT_EQ(range.start, 0u);
ASSERT_EQ(range.end, 1u);
- range = storage.OrderedIndexSearch(FilterOp::kLe, SqlValue::Long(2), indices);
+ range =
+ queryable->OrderedIndexSearch(FilterOp::kLe, SqlValue::Long(2), indices);
ASSERT_EQ(range.start, 0u);
ASSERT_EQ(range.end, 3u);
}
@@ -191,8 +206,10 @@
std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
SetIdStorage storage(&storage_data);
- Range range = storage.Search(FilterOp::kEq, SqlValue::Long(3), Range(4, 10))
- .TakeIfRange();
+ auto queryable = storage.MakeQueryable();
+ Range range =
+ queryable->Search(FilterOp::kEq, SqlValue::Long(3), Range(4, 10))
+ .TakeIfRange();
ASSERT_EQ(range.size(), 2u);
ASSERT_EQ(range.start, 4u);
@@ -203,7 +220,8 @@
std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
SetIdStorage storage(&storage_data);
- Range range = storage.Search(FilterOp::kEq, SqlValue::Long(9), Range(6, 9))
+ auto queryable = storage.MakeQueryable();
+ Range range = queryable->Search(FilterOp::kEq, SqlValue::Long(9), Range(6, 9))
.TakeIfRange();
ASSERT_EQ(range.size(), 0u);
}
@@ -212,8 +230,10 @@
std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
SetIdStorage storage(&storage_data);
- Range range = storage.Search(FilterOp::kEq, SqlValue::Long(12), Range(6, 9))
- .TakeIfRange();
+ auto queryable = storage.MakeQueryable();
+ Range range =
+ queryable->Search(FilterOp::kEq, SqlValue::Long(12), Range(6, 9))
+ .TakeIfRange();
ASSERT_EQ(range.size(), 0u);
}
@@ -221,21 +241,25 @@
std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
SetIdStorage storage(&storage_data);
- Range range = storage.Search(FilterOp::kEq, SqlValue::Long(100), Range(6, 9))
- .TakeIfRange();
+ auto queryable = storage.MakeQueryable();
+ Range range =
+ queryable->Search(FilterOp::kEq, SqlValue::Long(100), Range(6, 9))
+ .TakeIfRange();
ASSERT_EQ(range.size(), 0u);
}
TEST(SetIdStorage, IndexSearchEqTooBig) {
std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
SetIdStorage storage(&storage_data);
+ auto queryable = storage.MakeQueryable();
// {0, 3, 3, 6, 9, 9, 0, 3}
std::vector<uint32_t> indices_vec{1, 3, 5, 7, 9, 11, 2, 4};
Indices indices{indices_vec.data(), 8, Indices::State::kMonotonic};
- BitVector bv = storage.IndexSearch(FilterOp::kEq, SqlValue::Long(10), indices)
- .TakeIfBitVector();
+ BitVector bv =
+ queryable->IndexSearch(FilterOp::kEq, SqlValue::Long(10), indices)
+ .TakeIfBitVector();
ASSERT_EQ(bv.CountSetBits(), 0u);
}
@@ -243,43 +267,44 @@
TEST(SetIdStorage, SearchWithIdAsSimpleDoubleIsInt) {
std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
SetIdStorage storage(&storage_data);
+ auto queryable = storage.MakeQueryable();
SqlValue double_val = SqlValue::Double(7.0);
SqlValue long_val = SqlValue::Long(7);
Range range(1, 9);
FilterOp op = FilterOp::kEq;
- auto double_res = storage.Search(op, double_val, range);
- auto int_res = storage.Search(op, long_val, range);
+ auto double_res = queryable->Search(op, double_val, range);
+ auto int_res = queryable->Search(op, long_val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(double_res),
utils::ToIndexVectorForTests(int_res));
op = FilterOp::kNe;
- double_res = storage.Search(op, double_val, range);
- int_res = storage.Search(op, long_val, range);
+ double_res = queryable->Search(op, double_val, range);
+ int_res = queryable->Search(op, long_val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(double_res),
utils::ToIndexVectorForTests(int_res));
op = FilterOp::kLe;
- double_res = storage.Search(op, double_val, range);
- int_res = storage.Search(op, long_val, range);
+ double_res = queryable->Search(op, double_val, range);
+ int_res = queryable->Search(op, long_val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(double_res),
utils::ToIndexVectorForTests(int_res));
op = FilterOp::kLt;
- double_res = storage.Search(op, double_val, range);
- int_res = storage.Search(op, long_val, range);
+ double_res = queryable->Search(op, double_val, range);
+ int_res = queryable->Search(op, long_val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(double_res),
utils::ToIndexVectorForTests(int_res));
op = FilterOp::kGe;
- double_res = storage.Search(op, double_val, range);
- int_res = storage.Search(op, long_val, range);
+ double_res = queryable->Search(op, double_val, range);
+ int_res = queryable->Search(op, long_val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(double_res),
utils::ToIndexVectorForTests(int_res));
op = FilterOp::kGt;
- double_res = storage.Search(op, double_val, range);
- int_res = storage.Search(op, long_val, range);
+ double_res = queryable->Search(op, double_val, range);
+ int_res = queryable->Search(op, long_val, range);
ASSERT_EQ(utils::ToIndexVectorForTests(double_res),
utils::ToIndexVectorForTests(int_res));
}
@@ -287,29 +312,29 @@
TEST(SetIdStorage, SearchWithIdAsDouble) {
std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
SetIdStorage storage(&storage_data);
+ auto queryable = storage.MakeQueryable();
SqlValue val = SqlValue::Double(7.5);
Range range(5, 10);
- Range res = storage.Search(FilterOp::kEq, val, range).TakeIfRange();
+ Range res = queryable->Search(FilterOp::kEq, val, range).TakeIfRange();
ASSERT_EQ(res, Range());
- res = storage.Search(FilterOp::kNe, val, range).TakeIfRange();
+ res = queryable->Search(FilterOp::kNe, val, range).TakeIfRange();
ASSERT_EQ(res, Range(0, 10));
- res = storage.Search(FilterOp::kLe, val, range).TakeIfRange();
+ res = queryable->Search(FilterOp::kLe, val, range).TakeIfRange();
ASSERT_EQ(res, Range(5, 9));
- res = storage.Search(FilterOp::kLt, val, range).TakeIfRange();
+ res = queryable->Search(FilterOp::kLt, val, range).TakeIfRange();
ASSERT_EQ(res, Range(5, 9));
- res = storage.Search(FilterOp::kGe, val, range).TakeIfRange();
+ res = queryable->Search(FilterOp::kGe, val, range).TakeIfRange();
ASSERT_EQ(res, Range(9, 10));
- res = storage.Search(FilterOp::kGt, val, range).TakeIfRange();
+ res = queryable->Search(FilterOp::kGt, val, range).TakeIfRange();
ASSERT_EQ(res, Range(9, 10));
}
} // namespace
} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/db/column/string_storage.cc b/src/trace_processor/db/column/string_storage.cc
index b495892..53f061f 100644
--- a/src/trace_processor/db/column/string_storage.cc
+++ b/src/trace_processor/db/column/string_storage.cc
@@ -20,6 +20,7 @@
#include <cstdint>
#include <functional>
#include <iterator>
+#include <memory>
#include <string>
#include <utility>
#include <vector>
@@ -31,7 +32,7 @@
#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/containers/null_term_string_view.h"
#include "src/trace_processor/containers/string_pool.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/column/utils.h"
#include "src/trace_processor/tp_metatrace.h"
@@ -195,7 +196,21 @@
} // namespace
-SearchValidationResult StringStorage::ValidateSearchConstraints(
+StringStorage::StringStorage(StringPool* string_pool,
+ const std::vector<StringPool::Id>* data,
+ bool is_sorted)
+ : data_(data), string_pool_(string_pool), is_sorted_(is_sorted) {}
+
+std::unique_ptr<DataNode::Queryable> StringStorage::MakeQueryable() {
+ return std::make_unique<Queryable>(string_pool_, data_, is_sorted_);
+}
+
+StringStorage::Queryable::Queryable(StringPool* string_pool,
+ const std::vector<StringPool::Id>* data,
+ bool is_sorted)
+ : data_(data), string_pool_(string_pool), is_sorted_(is_sorted) {}
+
+SearchValidationResult StringStorage::Queryable::ValidateSearchConstraints(
SqlValue val,
FilterOp op) const {
// Type checks.
@@ -217,10 +232,10 @@
return SearchValidationResult::kOk;
}
-RangeOrBitVector StringStorage::Search(FilterOp op,
- SqlValue sql_val,
- Range search_range) const {
- PERFETTO_TP_TRACE(metatrace::Category::DB, "StringStorage::Search",
+RangeOrBitVector StringStorage::Queryable::Search(FilterOp op,
+ SqlValue sql_val,
+ Range search_range) const {
+ PERFETTO_TP_TRACE(metatrace::Category::DB, "StringStorage::Queryable::Search",
[&search_range, op](metatrace::Record* r) {
r->AddArg("Start", std::to_string(search_range.start));
r->AddArg("End", std::to_string(search_range.end));
@@ -259,23 +274,23 @@
return RangeOrBitVector(LinearSearch(op, sql_val, search_range));
}
-RangeOrBitVector StringStorage::IndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+RangeOrBitVector StringStorage::Queryable::IndexSearch(FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
PERFETTO_DCHECK(indices.size <= size());
- PERFETTO_TP_TRACE(metatrace::Category::DB, "StringStorage::IndexSearch",
- [indices, op](metatrace::Record* r) {
- r->AddArg("Count", std::to_string(indices.size));
- r->AddArg("Op",
- std::to_string(static_cast<uint32_t>(op)));
- });
+ PERFETTO_TP_TRACE(
+ metatrace::Category::DB, "StringStorage::Queryable::IndexSearch",
+ [indices, op](metatrace::Record* r) {
+ r->AddArg("Count", std::to_string(indices.size));
+ r->AddArg("Op", std::to_string(static_cast<uint32_t>(op)));
+ });
return RangeOrBitVector(
IndexSearchInternal(op, sql_val, indices.data, indices.size));
}
-BitVector StringStorage::LinearSearch(FilterOp op,
- SqlValue sql_val,
- Range range) const {
+BitVector StringStorage::Queryable::LinearSearch(FilterOp op,
+ SqlValue sql_val,
+ Range range) const {
StringPool::Id val =
(op == FilterOp::kIsNull || op == FilterOp::kIsNotNull)
? StringPool::Id::Null()
@@ -286,8 +301,7 @@
BitVector::Builder builder(range.end, range.start);
switch (op) {
case FilterOp::kEq:
- utils::LinearSearchWithComparator(
- val, start, std::equal_to<StringPool::Id>(), builder);
+ utils::LinearSearchWithComparator(val, start, std::equal_to<>(), builder);
break;
case FilterOp::kNe:
utils::LinearSearchWithComparator(val, start, NotEqual(), builder);
@@ -363,9 +377,9 @@
return std::move(builder).Build();
}
-Range StringStorage::OrderedIndexSearch(FilterOp op,
- SqlValue sql_val,
- Indices indices) const {
+Range StringStorage::Queryable::OrderedIndexSearch(FilterOp op,
+ SqlValue sql_val,
+ Indices indices) const {
StringPool::Id val =
(op == FilterOp::kIsNull || op == FilterOp::kIsNotNull)
? StringPool::Id::Null()
@@ -422,7 +436,7 @@
PERFETTO_FATAL("For GCC");
}
-RangeOrBitVector StringStorage::IndexSearchInternal(
+RangeOrBitVector StringStorage::Queryable::IndexSearchInternal(
FilterOp op,
SqlValue sql_val,
const uint32_t* indices,
@@ -437,8 +451,8 @@
switch (op) {
case FilterOp::kEq:
- utils::IndexSearchWithComparator(
- val, start, indices, std::equal_to<StringPool::Id>(), builder);
+ utils::IndexSearchWithComparator(val, start, indices, std::equal_to<>(),
+ builder);
break;
case FilterOp::kNe:
utils::IndexSearchWithComparator(val, start, indices, NotEqual(),
@@ -464,8 +478,8 @@
util::GlobMatcher matcher =
util::GlobMatcher::FromPattern(sql_val.AsString());
if (matcher.IsEquality()) {
- utils::IndexSearchWithComparator(
- val, start, indices, std::equal_to<StringPool::Id>(), builder);
+ utils::IndexSearchWithComparator(val, start, indices, std::equal_to<>(),
+ builder);
break;
}
utils::IndexSearchWithComparator(std::move(matcher), start, indices,
@@ -491,9 +505,10 @@
return RangeOrBitVector(std::move(builder).Build());
}
-Range StringStorage::BinarySearchIntrinsic(FilterOp op,
- SqlValue sql_val,
- Range search_range) const {
+Range StringStorage::Queryable::BinarySearchIntrinsic(
+ FilterOp op,
+ SqlValue sql_val,
+ Range search_range) const {
StringPool::Id val =
(op == FilterOp::kIsNull || op == FilterOp::kIsNotNull)
? StringPool::Id::Null()
@@ -502,27 +517,26 @@
switch (op) {
case FilterOp::kEq:
- return Range(LowerBoundIntrinsic(string_pool_, data_->data(), val_str,
- search_range),
- UpperBoundIntrinsic(string_pool_, data_->data(), val_str,
- search_range));
+ return {LowerBoundIntrinsic(string_pool_, data_->data(), val_str,
+ search_range),
+ UpperBoundIntrinsic(string_pool_, data_->data(), val_str,
+ search_range)};
case FilterOp::kLe:
- return Range(search_range.start,
- UpperBoundIntrinsic(string_pool_, data_->data(), val_str,
- search_range));
+ return {search_range.start,
+ UpperBoundIntrinsic(string_pool_, data_->data(), val_str,
+ search_range)};
case FilterOp::kLt:
- return Range(search_range.start,
- LowerBoundIntrinsic(string_pool_, data_->data(), val_str,
- search_range));
+ return {search_range.start,
+ LowerBoundIntrinsic(string_pool_, data_->data(), val_str,
+ search_range)};
case FilterOp::kGe:
- return Range(LowerBoundIntrinsic(string_pool_, data_->data(), val_str,
- search_range),
- search_range.end);
+ return {LowerBoundIntrinsic(string_pool_, data_->data(), val_str,
+ search_range),
+ search_range.end};
case FilterOp::kGt:
- return Range(UpperBoundIntrinsic(string_pool_, data_->data(), val_str,
- search_range),
- search_range.end);
-
+ return {UpperBoundIntrinsic(string_pool_, data_->data(), val_str,
+ search_range),
+ search_range.end};
case FilterOp::kNe:
case FilterOp::kIsNull:
case FilterOp::kIsNotNull:
@@ -533,7 +547,8 @@
PERFETTO_FATAL("For gcc");
}
-void StringStorage::StableSort(uint32_t* indices, uint32_t indices_size) const {
+void StringStorage::Queryable::StableSort(uint32_t* indices,
+ uint32_t indices_size) const {
std::stable_sort(indices, indices + indices_size,
[this](uint32_t a_idx, uint32_t b_idx) {
return string_pool_->Get((*data_)[a_idx]) <
@@ -541,7 +556,8 @@
});
}
-void StringStorage::Sort(uint32_t* indices, uint32_t indices_size) const {
+void StringStorage::Queryable::Sort(uint32_t* indices,
+ uint32_t indices_size) const {
std::sort(indices, indices + indices_size,
[this](uint32_t a_idx, uint32_t b_idx) {
return string_pool_->Get((*data_)[a_idx]) <
@@ -549,7 +565,7 @@
});
}
-void StringStorage::Serialize(StorageProto* msg) const {
+void StringStorage::Queryable::Serialize(StorageProto* msg) const {
auto* string_storage_msg = msg->set_string_storage();
string_storage_msg->set_is_sorted(is_sorted_);
diff --git a/src/trace_processor/db/column/string_storage.h b/src/trace_processor/db/column/string_storage.h
index d7bd958..da868ff 100644
--- a/src/trace_processor/db/column/string_storage.h
+++ b/src/trace_processor/db/column/string_storage.h
@@ -17,60 +17,74 @@
#define SRC_TRACE_PROCESSOR_DB_COLUMN_STRING_STORAGE_H_
#include <cstdint>
+#include <memory>
#include <string>
#include <vector>
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/containers/bit_vector.h"
#include "src/trace_processor/containers/string_pool.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/types.h"
namespace perfetto::trace_processor::column {
// Storage for String columns.
-class StringStorage final : public Column {
+class StringStorage final : public DataNode {
public:
StringStorage(StringPool* string_pool,
const std::vector<StringPool::Id>* data,
- bool is_sorted = false)
- : data_(data), string_pool_(string_pool), is_sorted_(is_sorted) {}
+ bool is_sorted = false);
- SearchValidationResult ValidateSearchConstraints(SqlValue,
- FilterOp) const override;
-
- RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
-
- RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
-
- Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
-
- void StableSort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Sort(uint32_t* rows, uint32_t rows_size) const override;
-
- void Serialize(StorageProto*) const override;
-
- uint32_t size() const override {
- return static_cast<uint32_t>(data_->size());
- }
-
- std::string DebugString() const override { return "StringStorage"; }
+ std::unique_ptr<DataNode::Queryable> MakeQueryable() override;
private:
- BitVector LinearSearch(FilterOp, SqlValue, Range) const;
+ class Queryable : public DataNode::Queryable {
+ public:
+ Queryable(StringPool* string_pool,
+ const std::vector<StringPool::Id>* data,
+ bool is_sorted);
- RangeOrBitVector IndexSearchInternal(FilterOp op,
- SqlValue sql_val,
- const uint32_t* indices,
- uint32_t indices_size) const;
+ SearchValidationResult ValidateSearchConstraints(SqlValue,
+ FilterOp) const override;
- Range BinarySearchIntrinsic(FilterOp op,
- SqlValue val,
- Range search_range) const;
+ RangeOrBitVector Search(FilterOp, SqlValue, Range) const override;
- // TODO(b/307482437): After the migration vectors should be owned by storage,
- // so change from pointer to value.
+ RangeOrBitVector IndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ Range OrderedIndexSearch(FilterOp, SqlValue, Indices) const override;
+
+ void StableSort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Sort(uint32_t* rows, uint32_t rows_size) const override;
+
+ void Serialize(StorageProto*) const override;
+
+ uint32_t size() const override {
+ return static_cast<uint32_t>(data_->size());
+ }
+
+ std::string DebugString() const override { return "StringStorage"; }
+
+ private:
+ BitVector LinearSearch(FilterOp, SqlValue, Range) const;
+
+ RangeOrBitVector IndexSearchInternal(FilterOp op,
+ SqlValue sql_val,
+ const uint32_t* indices,
+ uint32_t indices_size) const;
+
+ Range BinarySearchIntrinsic(FilterOp op,
+ SqlValue val,
+ Range search_range) const;
+
+ // TODO(b/307482437): After the migration vectors should be owned by
+ // storage, so change from pointer to value.
+ const std::vector<StringPool::Id>* data_ = nullptr;
+ StringPool* string_pool_ = nullptr;
+ const bool is_sorted_ = false;
+ };
+
const std::vector<StringPool::Id>* data_ = nullptr;
StringPool* string_pool_ = nullptr;
const bool is_sorted_ = false;
diff --git a/src/trace_processor/db/column/string_storage_unittest.cc b/src/trace_processor/db/column/string_storage_unittest.cc
index 7fb6464..e4ce5ac 100644
--- a/src/trace_processor/db/column/string_storage_unittest.cc
+++ b/src/trace_processor/db/column/string_storage_unittest.cc
@@ -15,14 +15,20 @@
*/
#include "src/trace_processor/db/column/string_storage.h"
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "perfetto/base/build_config.h"
+#include "perfetto/ext/base/string_view.h"
#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/containers/string_pool.h"
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/column/utils.h"
#include "test/gtest_and_gmock.h"
-namespace perfetto {
-namespace trace_processor {
-namespace column {
+namespace perfetto::trace_processor::column {
namespace {
using testing::ElementsAre;
@@ -38,43 +44,44 @@
}
ids.insert(ids.begin() + 3, StringPool::Id::Null());
StringStorage storage(&pool, &ids);
+ auto queriable = storage.MakeQueryable();
SqlValue val = SqlValue::String("pierogi");
Range filter_range(0, 7);
FilterOp op = FilterOp::kEq;
- auto res = storage.Search(op, val, filter_range);
+ auto res = queriable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(4));
op = FilterOp::kNe;
- res = storage.Search(op, val, filter_range);
+ res = queriable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 5, 6));
op = FilterOp::kLt;
- res = storage.Search(op, val, filter_range);
+ res = queriable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 5, 6));
op = FilterOp::kLe;
- res = storage.Search(op, val, filter_range);
+ res = queriable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 4, 5, 6));
op = FilterOp::kGt;
- res = storage.Search(op, val, filter_range);
+ res = queriable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2));
op = FilterOp::kGe;
- res = storage.Search(op, val, filter_range);
+ res = queriable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 4));
op = FilterOp::kIsNull;
- res = storage.Search(op, SqlValue(), filter_range);
+ res = queriable->Search(op, SqlValue(), filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3));
op = FilterOp::kIsNotNull;
- res = storage.Search(op, SqlValue(), filter_range);
+ res = queriable->Search(op, SqlValue(), filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 4, 5, 6));
op = FilterOp::kGlob;
- res = storage.Search(op, SqlValue::String("p*"), filter_range);
+ res = queriable->Search(op, SqlValue::String("p*"), filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(1, 2, 4));
}
@@ -88,45 +95,46 @@
}
ids.insert(ids.begin() + 3, StringPool::Id::Null());
StringStorage storage(&pool, &ids);
+ auto queriable = storage.MakeQueryable();
SqlValue val = SqlValue::String("pierogi");
// "fries", "onion", "pierogi", NULL, "pizza", "pasta", "cheese"
std::vector<uint32_t> indices_vec{6, 5, 4, 3, 2, 1, 0};
Indices indices{indices_vec.data(), 7, Indices::State::kNonmonotonic};
FilterOp op = FilterOp::kEq;
- auto res = storage.IndexSearch(op, val, indices);
+ auto res = queriable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2));
op = FilterOp::kNe;
- res = storage.IndexSearch(op, val, indices);
+ res = queriable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 4, 5, 6));
op = FilterOp::kLt;
- res = storage.IndexSearch(op, val, indices);
+ res = queriable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 5, 6));
op = FilterOp::kLe;
- res = storage.IndexSearch(op, val, indices);
+ res = queriable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 5, 6));
op = FilterOp::kGt;
- res = storage.IndexSearch(op, val, indices);
+ res = queriable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(4));
op = FilterOp::kGe;
- res = storage.IndexSearch(op, val, indices);
+ res = queriable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 4));
op = FilterOp::kIsNull;
- res = storage.IndexSearch(op, SqlValue(), indices);
+ res = queriable->IndexSearch(op, SqlValue(), indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3));
op = FilterOp::kIsNotNull;
- res = storage.IndexSearch(op, SqlValue(), indices);
+ res = queriable->IndexSearch(op, SqlValue(), indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2, 4, 5, 6));
op = FilterOp::kGlob;
- res = storage.IndexSearch(op, SqlValue::String("p*"), indices);
+ res = queriable->IndexSearch(op, SqlValue::String("p*"), indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 4, 5));
}
@@ -142,8 +150,10 @@
ids.insert(ids.begin() + 3, StringPool::Id::Null());
StringStorage storage(&pool, &ids);
+ auto queriable = storage.MakeQueryable();
BitVector bv =
- storage.Search(FilterOp::kRegex, SqlValue::String(".*zz.*"), Range(0, 7))
+ queriable
+ ->Search(FilterOp::kRegex, SqlValue::String(".*zz.*"), Range(0, 7))
.TakeIfBitVector();
ASSERT_EQ(bv.CountSetBits(), 1u);
@@ -160,8 +170,9 @@
ids.insert(ids.begin() + 3, StringPool::Id::Null());
StringStorage storage(&pool, &ids);
+ auto queriable = storage.MakeQueryable();
BitVector bv =
- storage.Search(FilterOp::kRegex, SqlValue::String("*"), Range(0, 7))
+ queriable->Search(FilterOp::kRegex, SqlValue::String("*"), Range(0, 7))
.TakeIfBitVector();
ASSERT_EQ(bv.CountSetBits(), 0u);
@@ -177,35 +188,36 @@
ids.push_back(pool.InternString(base::StringView(string)));
}
StringStorage storage(&pool, &ids, true);
+ auto queriable = storage.MakeQueryable();
SqlValue val = SqlValue::String("cheese");
Range filter_range(0, 6);
FilterOp op = FilterOp::kEq;
- auto res = storage.Search(op, val, filter_range);
+ auto res = queriable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2));
op = FilterOp::kNe;
- res = storage.Search(op, val, filter_range);
+ res = queriable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 3, 4, 5));
op = FilterOp::kLt;
- res = storage.Search(op, val, filter_range);
+ res = queriable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1));
op = FilterOp::kLe;
- res = storage.Search(op, val, filter_range);
+ res = queriable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
op = FilterOp::kGt;
- res = storage.Search(op, val, filter_range);
+ res = queriable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3, 4, 5));
op = FilterOp::kGe;
- res = storage.Search(op, val, filter_range);
+ res = queriable->Search(op, val, filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 3, 4, 5));
op = FilterOp::kGlob;
- res = storage.Search(op, SqlValue::String("*e"), filter_range);
+ res = queriable->Search(op, SqlValue::String("*e"), filter_range);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 2));
}
@@ -218,37 +230,38 @@
ids.push_back(pool.InternString(base::StringView(string)));
}
StringStorage storage(&pool, &ids, true);
+ auto queriable = storage.MakeQueryable();
SqlValue val = SqlValue::String("cheese");
// fries, eggplant, cheese, burger
std::vector<uint32_t> indices_vec{5, 4, 2, 1};
Indices indices{indices_vec.data(), 4, Indices::State::kNonmonotonic};
FilterOp op = FilterOp::kEq;
- auto res = storage.IndexSearch(op, val, indices);
+ auto res = queriable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2));
op = FilterOp::kNe;
- res = storage.IndexSearch(op, val, indices);
+ res = queriable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 3));
op = FilterOp::kLt;
- res = storage.IndexSearch(op, val, indices);
+ res = queriable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(3));
op = FilterOp::kLe;
- res = storage.IndexSearch(op, val, indices);
+ res = queriable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2, 3));
op = FilterOp::kGt;
- res = storage.IndexSearch(op, val, indices);
+ res = queriable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1));
op = FilterOp::kGe;
- res = storage.IndexSearch(op, val, indices);
+ res = queriable->IndexSearch(op, val, indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(0, 1, 2));
op = FilterOp::kGlob;
- res = storage.IndexSearch(op, SqlValue::String("*e"), indices);
+ res = queriable->IndexSearch(op, SqlValue::String("*e"), indices);
ASSERT_THAT(utils::ToIndexVectorForTests(res), ElementsAre(2));
}
@@ -261,33 +274,34 @@
ids.push_back(pool.InternString(base::StringView(string)));
}
StringStorage storage(&pool, &ids);
+ auto queriable = storage.MakeQueryable();
SqlValue val = SqlValue::String("pierogi");
// cheese, fries, onion, pasta, pierogi, pizza
std::vector<uint32_t> indices_vec{0, 5, 4, 1, 3, 2};
Indices indices{indices_vec.data(), 6, Indices::State::kNonmonotonic};
FilterOp op = FilterOp::kEq;
- Range res = storage.OrderedIndexSearch(op, val, indices);
+ Range res = queriable->OrderedIndexSearch(op, val, indices);
ASSERT_EQ(res.start, 4u);
ASSERT_EQ(res.end, 5u);
op = FilterOp::kLt;
- res = storage.OrderedIndexSearch(op, val, indices);
+ res = queriable->OrderedIndexSearch(op, val, indices);
ASSERT_EQ(res.start, 0u);
ASSERT_EQ(res.end, 4u);
op = FilterOp::kLe;
- res = storage.OrderedIndexSearch(op, val, indices);
+ res = queriable->OrderedIndexSearch(op, val, indices);
ASSERT_EQ(res.start, 0u);
ASSERT_EQ(res.end, 5u);
op = FilterOp::kGt;
- res = storage.OrderedIndexSearch(op, val, indices);
+ res = queriable->OrderedIndexSearch(op, val, indices);
ASSERT_EQ(res.start, 5u);
ASSERT_EQ(res.end, 6u);
op = FilterOp::kGe;
- res = storage.OrderedIndexSearch(op, val, indices);
+ res = queriable->OrderedIndexSearch(op, val, indices);
ASSERT_EQ(res.start, 4u);
ASSERT_EQ(res.end, 6u);
}
@@ -301,10 +315,12 @@
ids.push_back(pool.InternString(base::StringView(string)));
}
StringStorage storage(&pool, &ids);
+ auto queriable = storage.MakeQueryable();
std::vector<uint32_t> indices_vec{0, 2, 5, 7};
Indices indices{indices_vec.data(), 4, Indices::State::kNonmonotonic};
- auto res = storage.OrderedIndexSearch(FilterOp::kIsNull, SqlValue(), indices);
+ auto res =
+ queriable->OrderedIndexSearch(FilterOp::kIsNull, SqlValue(), indices);
ASSERT_EQ(res.start, 0u);
ASSERT_EQ(res.end, 2u);
}
@@ -318,16 +334,15 @@
ids.push_back(pool.InternString(base::StringView(string)));
}
StringStorage storage(&pool, &ids);
+ auto queriable = storage.MakeQueryable();
std::vector<uint32_t> indices_vec{0, 2, 5, 7};
Indices indices{indices_vec.data(), 4, Indices::State::kNonmonotonic};
auto res =
- storage.OrderedIndexSearch(FilterOp::kIsNotNull, SqlValue(), indices);
+ queriable->OrderedIndexSearch(FilterOp::kIsNotNull, SqlValue(), indices);
ASSERT_EQ(res.start, 2u);
ASSERT_EQ(res.end, 4u);
}
} // namespace
-} // namespace column
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::column
diff --git a/src/trace_processor/db/query_executor.cc b/src/trace_processor/db/query_executor.cc
index 226e75a..b7f23c8 100644
--- a/src/trace_processor/db/query_executor.cc
+++ b/src/trace_processor/db/query_executor.cc
@@ -14,20 +14,22 @@
* limitations under the License.
*/
-#include <array>
-#include <cmath>
-#include <cstddef>
+#include <algorithm>
+#include <cstdint>
#include <memory>
-#include <numeric>
#include <optional>
+#include <utility>
#include <vector>
#include "perfetto/base/logging.h"
-#include "perfetto/ext/base/status_or.h"
+#include "perfetto/ext/base/small_vector.h"
#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/containers/row_map.h"
#include "src/trace_processor/containers/string_pool.h"
+#include "src/trace_processor/db/column.h"
#include "src/trace_processor/db/column/arrangement_overlay.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/dense_null_overlay.h"
#include "src/trace_processor/db/column/dummy_storage.h"
#include "src/trace_processor/db/column/id_storage.h"
@@ -40,18 +42,16 @@
#include "src/trace_processor/db/query_executor.h"
#include "src/trace_processor/db/table.h"
-namespace perfetto {
-namespace trace_processor {
+namespace perfetto::trace_processor {
namespace {
using Range = RowMap::Range;
-using Storage = column::Column;
} // namespace
void QueryExecutor::FilterColumn(const Constraint& c,
- const column::Column& storage,
+ const column::DataNode::Queryable& queryable,
RowMap* rm) {
// Shortcut of empty row map.
if (rm->empty())
@@ -65,7 +65,7 @@
return;
}
- switch (storage.ValidateSearchConstraints(c.value, c.op)) {
+ switch (queryable.ValidateSearchConstraints(c.value, c.op)) {
case SearchValidationResult::kAllData:
return;
case SearchValidationResult::kNoData:
@@ -88,20 +88,20 @@
rm->IsIndexVector() || rm_size < 1024 || rm_size * 10 < range_size;
if (!disallows_index_search && prefers_index_search) {
- IndexSearch(c, storage, rm);
+ IndexSearch(c, queryable, rm);
return;
}
- LinearSearch(c, storage, rm);
+ LinearSearch(c, queryable, rm);
}
void QueryExecutor::LinearSearch(const Constraint& c,
- const column::Column& storage,
+ const column::DataNode::Queryable& queryable,
RowMap* rm) {
// TODO(b/283763282): Align these to word boundaries.
Range bounds(rm->Get(0), rm->Get(rm->size() - 1) + 1);
// Search the storage.
- RangeOrBitVector res = storage.Search(c.op, c.value, bounds);
+ RangeOrBitVector res = queryable.Search(c.op, c.value, bounds);
if (rm->IsRange()) {
if (res.IsRange()) {
Range range = std::move(res).TakeIfRange();
@@ -123,12 +123,12 @@
}
void QueryExecutor::IndexSearch(const Constraint& c,
- const column::Column& storage,
+ const column::DataNode::Queryable& queryable,
RowMap* rm) {
// Create outmost TableIndexVector.
std::vector<uint32_t> table_indices = std::move(*rm).TakeAsIndexVector();
- RangeOrBitVector matched = storage.IndexSearch(
+ RangeOrBitVector matched = queryable.IndexSearch(
c.op, c.value,
Indices{table_indices.data(), static_cast<uint32_t>(table_indices.size()),
Indices::State::kMonotonic});
@@ -184,105 +184,133 @@
}
// Create storage
- std::unique_ptr<column::Column> storage;
+ base::SmallVector<std::unique_ptr<column::DataNode>, 4> data_nodes;
+ std::unique_ptr<column::DataNode::Queryable> queryable;
if (col.IsSetId()) {
if (col.IsNullable()) {
- storage = std::make_unique<column::SetIdStorage>(
- &col.storage<std::optional<uint32_t>>().non_null_vector());
+ data_nodes.emplace_back(std::make_unique<column::SetIdStorage>(
+ &col.storage<std::optional<uint32_t>>().non_null_vector()));
+ queryable = data_nodes.back()->MakeQueryable();
} else {
- storage = std::make_unique<column::SetIdStorage>(
- &col.storage<uint32_t>().vector());
+ data_nodes.emplace_back(std::make_unique<column::SetIdStorage>(
+ &col.storage<uint32_t>().vector()));
+ queryable = data_nodes.back()->MakeQueryable();
}
} else {
switch (col.col_type()) {
case ColumnType::kDummy:
- storage = std::make_unique<column::DummyStorage>();
+ data_nodes.emplace_back(std::make_unique<column::DummyStorage>());
+ queryable = data_nodes.back()->MakeQueryable();
break;
case ColumnType::kId:
- storage = std::make_unique<column::IdStorage>(column_size);
+ data_nodes.emplace_back(
+ std::make_unique<column::IdStorage>(column_size));
+ queryable = data_nodes.back()->MakeQueryable();
break;
case ColumnType::kString:
- storage = std::make_unique<column::StringStorage>(
+ data_nodes.emplace_back(std::make_unique<column::StringStorage>(
table->string_pool(), &col.storage<StringPool::Id>().vector(),
- col.IsSorted());
+ col.IsSorted()));
+ queryable = data_nodes.back()->MakeQueryable();
break;
case ColumnType::kInt64:
if (col.IsNullable()) {
- storage = std::make_unique<column::NumericStorage<int64_t>>(
- &col.storage<std::optional<int64_t>>().non_null_vector(),
- col.col_type(), col.IsSorted());
+ data_nodes.emplace_back(
+ std::make_unique<column::NumericStorage<int64_t>>(
+ &col.storage<std::optional<int64_t>>().non_null_vector(),
+ col.col_type(), col.IsSorted()));
+ queryable = data_nodes.back()->MakeQueryable();
} else {
- storage = std::make_unique<column::NumericStorage<int64_t>>(
- &col.storage<int64_t>().vector(), col.col_type(),
- col.IsSorted());
+ data_nodes.emplace_back(
+ std::make_unique<column::NumericStorage<int64_t>>(
+ &col.storage<int64_t>().vector(), col.col_type(),
+ col.IsSorted()));
+ queryable = data_nodes.back()->MakeQueryable();
}
break;
case ColumnType::kUint32:
if (col.IsNullable()) {
- storage = std::make_unique<column::NumericStorage<uint32_t>>(
- &col.storage<std::optional<uint32_t>>().non_null_vector(),
- col.col_type(), col.IsSorted());
+ data_nodes.emplace_back(
+ std::make_unique<column::NumericStorage<uint32_t>>(
+ &col.storage<std::optional<uint32_t>>().non_null_vector(),
+ col.col_type(), col.IsSorted()));
+ queryable = data_nodes.back()->MakeQueryable();
} else {
- storage = std::make_unique<column::NumericStorage<uint32_t>>(
- &col.storage<uint32_t>().vector(), col.col_type(),
- col.IsSorted());
+ data_nodes.emplace_back(
+ std::make_unique<column::NumericStorage<uint32_t>>(
+ &col.storage<uint32_t>().vector(), col.col_type(),
+ col.IsSorted()));
+ queryable = data_nodes.back()->MakeQueryable();
}
break;
case ColumnType::kInt32:
if (col.IsNullable()) {
- storage = std::make_unique<column::NumericStorage<int32_t>>(
- &col.storage<std::optional<int32_t>>().non_null_vector(),
- col.col_type(), col.IsSorted());
+ data_nodes.emplace_back(
+ std::make_unique<column::NumericStorage<int32_t>>(
+ &col.storage<std::optional<int32_t>>().non_null_vector(),
+ col.col_type(), col.IsSorted()));
+ queryable = data_nodes.back()->MakeQueryable();
} else {
- storage = std::make_unique<column::NumericStorage<int32_t>>(
- &col.storage<int32_t>().vector(), col.col_type(),
- col.IsSorted());
+ data_nodes.emplace_back(
+ std::make_unique<column::NumericStorage<int32_t>>(
+ &col.storage<int32_t>().vector(), col.col_type(),
+ col.IsSorted()));
+ queryable = data_nodes.back()->MakeQueryable();
}
break;
case ColumnType::kDouble:
if (col.IsNullable()) {
- storage = std::make_unique<column::NumericStorage<double>>(
- &col.storage<std::optional<double>>().non_null_vector(),
- col.col_type(), col.IsSorted());
+ data_nodes.emplace_back(
+ std::make_unique<column::NumericStorage<double>>(
+ &col.storage<std::optional<double>>().non_null_vector(),
+ col.col_type(), col.IsSorted()));
+ queryable = data_nodes.back()->MakeQueryable();
} else {
- storage = std::make_unique<column::NumericStorage<double>>(
- &col.storage<double>().vector(), col.col_type(),
- col.IsSorted());
+ data_nodes.emplace_back(
+ std::make_unique<column::NumericStorage<double>>(
+ &col.storage<double>().vector(), col.col_type(),
+ col.IsSorted()));
+ queryable = data_nodes.back()->MakeQueryable();
}
}
}
+
if (col.IsNullable()) {
// String columns are inherently nullable: null values are signified
// with Id::Null().
PERFETTO_CHECK(col.col_type() != ColumnType::kString);
if (col.IsDense()) {
- storage = std::make_unique<column::DenseNullOverlay>(
- std::move(storage), col.storage_base().bv());
+ data_nodes.emplace_back(std::make_unique<column::DenseNullOverlay>(
+ col.storage_base().bv()));
+ queryable = data_nodes.back()->MakeQueryable(std::move(queryable));
} else {
- storage = std::make_unique<column::NullOverlay>(
- std::move(storage), col.storage_base().bv());
+ data_nodes.emplace_back(
+ std::make_unique<column::NullOverlay>(col.storage_base().bv()));
+ queryable = data_nodes.back()->MakeQueryable(std::move(queryable));
}
}
if (col.overlay().row_map().IsIndexVector()) {
- storage = std::make_unique<column::ArrangementOverlay>(
- std::move(storage), col.overlay().row_map().GetIfIndexVector(),
- col.IsSorted());
+ data_nodes.emplace_back(std::make_unique<column::ArrangementOverlay>(
+ col.overlay().row_map().GetIfIndexVector(), col.IsSorted()));
+ queryable = data_nodes.back()->MakeQueryable(std::move(queryable));
}
if (col.overlay().row_map().IsBitVector()) {
- storage = std::make_unique<column::SelectorOverlay>(
- std::move(storage), col.overlay().row_map().GetIfBitVector());
+ data_nodes.emplace_back(std::make_unique<column::SelectorOverlay>(
+ col.overlay().row_map().GetIfBitVector()));
+ queryable = data_nodes.back()->MakeQueryable(std::move(queryable));
}
uint32_t pre_count = rm.size();
- FilterColumn(c, *storage.get(), &rm);
+ FilterColumn(c, *queryable, &rm);
PERFETTO_DCHECK(rm.size() <= pre_count);
}
return rm;
}
-void QueryExecutor::BoundedColumnFilterForTesting(const Constraint& c,
- const column::Column& col,
- RowMap* rm) {
+void QueryExecutor::BoundedColumnFilterForTesting(
+ const Constraint& c,
+ const column::DataNode::Queryable& col,
+ RowMap* rm) {
switch (col.ValidateSearchConstraints(c.value, c.op)) {
case SearchValidationResult::kAllData:
return;
@@ -296,9 +324,10 @@
LinearSearch(c, col, rm);
}
-void QueryExecutor::IndexedColumnFilterForTesting(const Constraint& c,
- const column::Column& col,
- RowMap* rm) {
+void QueryExecutor::IndexedColumnFilterForTesting(
+ const Constraint& c,
+ const column::DataNode::Queryable& col,
+ RowMap* rm) {
switch (col.ValidateSearchConstraints(c.value, c.op)) {
case SearchValidationResult::kAllData:
return;
@@ -312,5 +341,4 @@
IndexSearch(c, col, rm);
}
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/db/query_executor.h b/src/trace_processor/db/query_executor.h
index e5feff5..863382d 100644
--- a/src/trace_processor/db/query_executor.h
+++ b/src/trace_processor/db/query_executor.h
@@ -16,14 +16,16 @@
#ifndef SRC_TRACE_PROCESSOR_DB_QUERY_EXECUTOR_H_
#define SRC_TRACE_PROCESSOR_DB_QUERY_EXECUTOR_H_
+#include <cstdint>
#include <vector>
+#include "perfetto/base/logging.h"
#include "src/trace_processor/containers/row_map.h"
#include "src/trace_processor/db/column.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
+#include "src/trace_processor/db/column/types.h"
-namespace perfetto {
-namespace trace_processor {
+namespace perfetto::trace_processor {
// Responsible for executing filtering/sorting operations on a single Table.
// TODO(b/283763282): Introduce sorting.
@@ -32,7 +34,8 @@
static constexpr uint32_t kMaxOverlayCount = 8;
// |row_count| is the size of the last overlay.
- QueryExecutor(const std::vector<column::Column*>& columns, uint32_t row_count)
+ QueryExecutor(const std::vector<column::DataNode::Queryable*>& columns,
+ uint32_t row_count)
: columns_(columns), row_count_(row_count) {}
// Apply all the constraints on the data and return the filtered RowMap.
@@ -44,48 +47,43 @@
return rm;
}
- // Sorts using vector of Order.
- // TODO(b/283763282): Implement.
- RowMap Sort(const std::vector<Order>&) { PERFETTO_FATAL("Not implemented."); }
-
// Enables QueryExecutor::Filter on Table columns.
static RowMap FilterLegacy(const Table*, const std::vector<Constraint>&);
- // Enables QueryExecutor::Sort on Table columns.
- // TODO(b/283763282): Implement.
- static RowMap SortLegacy(const Table*, const std::vector<Order>&) {
- PERFETTO_FATAL("Not implemented.");
- }
-
// Used only in unittests. Exposes private function.
static void BoundedColumnFilterForTesting(const Constraint&,
- const column::Column&,
+ const column::DataNode::Queryable&,
RowMap*);
// Used only in unittests. Exposes private function.
static void IndexedColumnFilterForTesting(const Constraint&,
- const column::Column&,
+ const column::DataNode::Queryable&,
RowMap*);
private:
// Updates RowMap with result of filtering single column using the Constraint.
- static void FilterColumn(const Constraint&, const column::Column&, RowMap*);
+ static void FilterColumn(const Constraint&,
+ const column::DataNode::Queryable&,
+ RowMap*);
// Filters the column using Range algorithm - tries to find the smallest Range
// to filter the storage with.
- static void LinearSearch(const Constraint&, const column::Column&, RowMap*);
+ static void LinearSearch(const Constraint&,
+ const column::DataNode::Queryable&,
+ RowMap*);
// Filters the column using Index algorithm - finds the indices to filter the
// storage with.
- static void IndexSearch(const Constraint&, const column::Column&, RowMap*);
+ static void IndexSearch(const Constraint&,
+ const column::DataNode::Queryable&,
+ RowMap*);
- std::vector<column::Column*> columns_;
+ std::vector<column::DataNode::Queryable*> columns_;
// Number of rows in the outmost overlay.
uint32_t row_count_ = 0;
};
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
#endif // SRC_TRACE_PROCESSOR_DB_QUERY_EXECUTOR_H_
diff --git a/src/trace_processor/db/query_executor_unittest.cc b/src/trace_processor/db/query_executor_unittest.cc
index b3a1bc5..ecff6a6 100644
--- a/src/trace_processor/db/query_executor_unittest.cc
+++ b/src/trace_processor/db/query_executor_unittest.cc
@@ -16,9 +16,20 @@
#include "src/trace_processor/db/query_executor.h"
+#include <algorithm>
+#include <cstdint>
+#include <memory>
+#include <numeric>
+#include <string>
+#include <vector>
+
+#include "perfetto/ext/base/string_view.h"
#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/containers/bit_vector.h"
+#include "src/trace_processor/containers/row_map.h"
+#include "src/trace_processor/containers/string_pool.h"
#include "src/trace_processor/db/column/arrangement_overlay.h"
-#include "src/trace_processor/db/column/column.h"
+#include "src/trace_processor/db/column/data_node.h"
#include "src/trace_processor/db/column/fake_storage.h"
#include "src/trace_processor/db/column/id_storage.h"
#include "src/trace_processor/db/column/null_overlay.h"
@@ -26,10 +37,10 @@
#include "src/trace_processor/db/column/selector_overlay.h"
#include "src/trace_processor/db/column/set_id_storage.h"
#include "src/trace_processor/db/column/string_storage.h"
+#include "src/trace_processor/db/column/types.h"
#include "test/gtest_and_gmock.h"
-namespace perfetto {
-namespace trace_processor {
+namespace perfetto::trace_processor {
namespace {
using testing::ElementsAre;
@@ -44,10 +55,11 @@
TEST(QueryExecutor, OnlyStorageRange) {
std::vector<int64_t> storage_data{1, 2, 3, 4, 5};
column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto queryable = storage.MakeQueryable();
Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
- RowMap rm(0, storage.size());
- QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
+ RowMap rm(0, queryable->size());
+ QueryExecutor::BoundedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_EQ(rm.size(), 3u);
ASSERT_EQ(rm.Get(0), 2u);
@@ -56,10 +68,11 @@
TEST(QueryExecutor, OnlyStorageRangeIsNull) {
std::vector<int64_t> storage_data{1, 2, 3, 4, 5};
column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto queryable = storage.MakeQueryable();
Constraint c{0, FilterOp::kIsNull, SqlValue()};
RowMap rm(0, 5);
- QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
+ QueryExecutor::BoundedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_EQ(rm.size(), 0u);
}
@@ -71,10 +84,11 @@
std::transform(storage_data.begin(), storage_data.end(), storage_data.begin(),
[](int64_t n) { return n % 5; });
column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto queryable = storage.MakeQueryable();
Constraint c{0, FilterOp::kLt, SqlValue::Long(2)};
RowMap rm(0, 10);
- QueryExecutor::IndexedColumnFilterForTesting(c, storage, &rm);
+ QueryExecutor::IndexedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_EQ(rm.size(), 4u);
ASSERT_EQ(rm.Get(0), 0u);
@@ -86,10 +100,11 @@
TEST(QueryExecutor, OnlyStorageIndexIsNull) {
std::vector<int64_t> storage_data{1, 2, 3, 4, 5};
column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto queryable = storage.MakeQueryable();
Constraint c{0, FilterOp::kIsNull, SqlValue()};
RowMap rm(0, 5);
- QueryExecutor::IndexedColumnFilterForTesting(c, storage, &rm);
+ QueryExecutor::IndexedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_EQ(rm.size(), 0u);
}
@@ -100,11 +115,12 @@
auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
&storage_data, ColumnType::kInt64);
BitVector bv{1, 1, 0, 1, 1, 0, 0, 0, 1, 0};
- column::NullOverlay storage(std::move(numeric), &bv);
+ column::NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(numeric->MakeQueryable());
Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
RowMap rm(0, 10);
- QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
+ QueryExecutor::BoundedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_EQ(rm.size(), 2u);
ASSERT_EQ(rm.Get(0), 4u);
@@ -118,11 +134,12 @@
&storage_data, ColumnType::kInt64);
BitVector bv{1, 1, 0, 1, 1, 0, 0, 0, 1, 0};
- column::NullOverlay storage(std::move(numeric), &bv);
+ column::NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(numeric->MakeQueryable());
Constraint c{0, FilterOp::kIsNull, SqlValue()};
- RowMap rm(0, storage.size());
- QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
+ RowMap rm(0, queryable->size());
+ QueryExecutor::BoundedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_EQ(rm.size(), 5u);
ASSERT_EQ(rm.Get(0), 2u);
@@ -141,11 +158,12 @@
&storage_data, ColumnType::kInt64);
BitVector bv{1, 1, 0, 1, 1, 0, 1, 0, 0, 1};
- column::NullOverlay storage(std::move(numeric), &bv);
+ column::NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(numeric->MakeQueryable());
Constraint c{0, FilterOp::kGe, SqlValue::Long(1)};
RowMap rm(0, 10);
- QueryExecutor::IndexedColumnFilterForTesting(c, storage, &rm);
+ QueryExecutor::IndexedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_EQ(rm.size(), 4u);
ASSERT_EQ(rm.Get(0), 1u);
@@ -161,11 +179,12 @@
&storage_data, ColumnType::kInt64);
BitVector bv{1, 1, 0, 1, 1, 0, 0, 0, 1, 0};
- column::NullOverlay storage(std::move(numeric), &bv);
+ column::NullOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(numeric->MakeQueryable());
Constraint c{0, FilterOp::kIsNull, SqlValue()};
RowMap rm(0, 10);
- QueryExecutor::IndexedColumnFilterForTesting(c, storage, &rm);
+ QueryExecutor::IndexedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_EQ(rm.size(), 5u);
ASSERT_EQ(rm.Get(0), 2u);
@@ -182,11 +201,12 @@
&storage_data, ColumnType::kInt64);
BitVector bv{1, 1, 0, 0, 1};
- SelectorOverlay storage(std::move(numeric), &bv);
+ SelectorOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(numeric->MakeQueryable());
Constraint c{0, FilterOp::kGt, SqlValue::Long(1)};
RowMap rm(0, 3);
- QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
+ QueryExecutor::BoundedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u));
}
@@ -200,11 +220,12 @@
&storage_data, ColumnType::kInt64);
BitVector bv{1, 1, 0, 1, 1, 0, 1, 0, 0, 1};
- SelectorOverlay storage(std::move(numeric), &bv);
+ SelectorOverlay storage(&bv);
+ auto queryable = storage.MakeQueryable(numeric->MakeQueryable());
Constraint c{0, FilterOp::kGe, SqlValue::Long(2)};
RowMap rm(0, 6);
- QueryExecutor::IndexedColumnFilterForTesting(c, storage, &rm);
+ QueryExecutor::IndexedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u, 3u, 5u));
}
@@ -216,39 +237,40 @@
&storage_data, ColumnType::kInt64);
std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
- ArrangementOverlay storage(std::move(numeric), &arrangement, false);
+ ArrangementOverlay storage(&arrangement, false);
+ auto queryable = storage.MakeQueryable(numeric->MakeQueryable());
Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
RowMap rm(0, 5);
- QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
+ QueryExecutor::BoundedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_THAT(rm.GetAllIndices(), ElementsAre(0u, 4u));
}
TEST(QueryExecutor, ArrangementOverlaySubsetInputRange) {
- std::unique_ptr<column::Column> fake =
- column::FakeStorage::SearchSubset(5u, RowMap::Range(2u, 4u));
+ auto fake = column::FakeStorage::SearchSubset(5u, RowMap::Range(2u, 4u));
std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
- ArrangementOverlay storage(std::move(fake), &arrangement, false);
+ ArrangementOverlay storage(&arrangement, false);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
Constraint c{0, FilterOp::kGe, SqlValue::Long(0u)};
RowMap rm(1, 3);
- QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
+ QueryExecutor::BoundedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u));
}
TEST(QueryExecutor, ArrangementOverlaySubsetInputBitvector) {
- std::unique_ptr<column::Column> fake =
- column::FakeStorage::SearchSubset(5u, BitVector({0, 0, 1, 1, 0}));
+ auto fake = column::FakeStorage::SearchSubset(5u, BitVector({0, 0, 1, 1, 0}));
std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
- ArrangementOverlay storage(std::move(fake), &arrangement, false);
+ ArrangementOverlay storage(&arrangement, false);
+ auto queryable = storage.MakeQueryable(fake->MakeQueryable());
Constraint c{0, FilterOp::kGe, SqlValue::Long(0u)};
RowMap rm(1, 3);
- QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
+ QueryExecutor::BoundedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u));
}
@@ -260,11 +282,12 @@
&storage_data, ColumnType::kInt64);
std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
- ArrangementOverlay storage(std::move(numeric), &arrangement, false);
+ ArrangementOverlay storage(&arrangement, false);
+ auto queryable = storage.MakeQueryable(numeric->MakeQueryable());
Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
RowMap rm(0, 5);
- QueryExecutor::IndexedColumnFilterForTesting(c, storage, &rm);
+ QueryExecutor::IndexedColumnFilterForTesting(c, *queryable, &rm);
ASSERT_THAT(rm.GetAllIndices(), ElementsAre(0u, 4u));
}
@@ -272,10 +295,11 @@
TEST(QueryExecutor, MismatchedTypeNullWithOtherOperations) {
std::vector<int64_t> storage_data{0, 1, 2, 3, 0, 1, 2, 3};
column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64);
+ auto queryable = storage.MakeQueryable();
// Filter.
Constraint c{0, FilterOp::kGe, SqlValue()};
- QueryExecutor exec({&storage}, 6);
+ QueryExecutor exec({queryable.get()}, 6);
RowMap res = exec.Filter({c});
ASSERT_TRUE(res.empty());
@@ -289,17 +313,18 @@
// Current vector
// 0, 1, NULL, 2, 3, 0, NULL, NULL, 1, 2, 3, NULL
BitVector null_bv{1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0};
- auto null =
- std::make_unique<column::NullOverlay>(std::move(numeric), &null_bv);
+ auto null = std::make_unique<column::NullOverlay>(&null_bv);
// Final vector
// 0, NULL, 3, NULL, 1, 3
BitVector selector_bv{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
- SelectorOverlay storage(std::move(null), &selector_bv);
+ SelectorOverlay storage(&selector_bv);
+ auto queryable =
+ storage.MakeQueryable(null->MakeQueryable(numeric->MakeQueryable()));
// Filter.
Constraint c{0, FilterOp::kGe, SqlValue::Long(2)};
- QueryExecutor exec({&storage}, 6);
+ QueryExecutor exec({queryable.get()}, 6);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 2u);
@@ -315,17 +340,18 @@
// Current vector
// 0, 1, NULL, 2, 3, 0, NULL, NULL, 1, 2, 3, NULL
BitVector null_bv{1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0};
- auto null =
- std::make_unique<column::NullOverlay>(std::move(numeric), &null_bv);
+ auto null = std::make_unique<column::NullOverlay>(&null_bv);
// Final vector
// NULL, 3, NULL, NULL, 3, NULL
std::vector<uint32_t> arrangement{2, 4, 6, 2, 4, 6};
- ArrangementOverlay storage(std::move(null), &arrangement, false);
+ ArrangementOverlay storage(&arrangement, false);
+ auto queryable =
+ storage.MakeQueryable(null->MakeQueryable(numeric->MakeQueryable()));
// Filter.
Constraint c{0, FilterOp::kGe, SqlValue::Long(1)};
- QueryExecutor exec({&storage}, 6);
+ QueryExecutor exec({queryable.get()}, 6);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 2u);
@@ -341,17 +367,18 @@
// Current vector
// 0, 1, NULL, 2, 3, 0, NULL, NULL, 1, 2, 3, NULL
BitVector null_bv{1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0};
- auto null =
- std::make_unique<column::NullOverlay>(std::move(numeric), &null_bv);
+ auto null = std::make_unique<column::NullOverlay>(&null_bv);
// Final vector
// 0, NULL, 3, NULL, 1, 3
BitVector selector_bv{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
- SelectorOverlay storage(std::move(null), &selector_bv);
+ SelectorOverlay storage(&selector_bv);
+ auto queryable =
+ storage.MakeQueryable(null->MakeQueryable(numeric->MakeQueryable()));
// Filter.
Constraint c{0, FilterOp::kIsNull, SqlValue()};
- QueryExecutor exec({&storage}, 6);
+ QueryExecutor exec({queryable.get()}, 6);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 2u);
@@ -366,16 +393,18 @@
// Add nulls - {0, 1, NULL, NULL, 2, 3, NULL, NULL, 4, 5, 6, NULL}
BitVector null_bv{1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0};
- auto null =
- std::make_unique<column::NullOverlay>(std::move(numeric), &null_bv);
+ auto null = std::make_unique<column::NullOverlay>(&null_bv);
// Final vector {1, NULL, 3, NULL, 5, NULL}.
BitVector selector_bv{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
- SelectorOverlay storage(std::move(null), &selector_bv);
+ SelectorOverlay storage(&selector_bv);
+
+ auto queryable =
+ storage.MakeQueryable(null->MakeQueryable(numeric->MakeQueryable()));
// Filter.
Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
- QueryExecutor exec({&storage}, 6);
+ QueryExecutor exec({queryable.get()}, 6);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 2u);
@@ -390,16 +419,18 @@
// Select 6 elements from storage, resulting in a vector {0, 1, 3, 4, 6, 7}.
BitVector selector_bv{1, 1, 0, 1, 1, 0, 1, 1, 0, 0};
- auto selector =
- std::make_unique<SelectorOverlay>(std::move(numeric), &selector_bv);
+ auto selector = std::make_unique<SelectorOverlay>(&selector_bv);
// Add nulls, final vector {NULL, NULL, NULL 0, 1, 3, 4, 6, 7}.
BitVector null_bv{0, 0, 0, 1, 1, 1, 1, 1, 1};
- column::NullOverlay storage(std::move(selector), &null_bv);
+ column::NullOverlay storage(&null_bv);
+
+ auto queryable =
+ storage.MakeQueryable(selector->MakeQueryable(numeric->MakeQueryable()));
// Filter.
Constraint c{0, FilterOp::kIsNull, SqlValue()};
- QueryExecutor exec({&storage}, 9);
+ QueryExecutor exec({queryable.get()}, 9);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 3u);
@@ -414,16 +445,18 @@
// Select 6 elements from storage, resulting in a vector {0, 3, 3, 6, 9, 9}.
BitVector selector_bv{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
- auto selector =
- std::make_unique<SelectorOverlay>(std::move(numeric), &selector_bv);
+ auto selector = std::make_unique<SelectorOverlay>(&selector_bv);
// Add nulls - vector (size 10) {NULL, 0, 3, NULL, 3, 6, NULL, 9, 9, NULL}.
BitVector null_bv{0, 1, 1, 0, 1, 1, 0, 1, 1, 0};
- column::NullOverlay storage(std::move(selector), &null_bv);
+ column::NullOverlay storage(&null_bv);
+
+ auto queryable =
+ storage.MakeQueryable(selector->MakeQueryable(numeric->MakeQueryable()));
// Filter.
Constraint c{0, FilterOp::kIsNull, SqlValue()};
- QueryExecutor exec({&storage}, 10);
+ QueryExecutor exec({queryable.get()}, 10);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 4u);
@@ -437,10 +470,11 @@
std::vector<int64_t> storage_data{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64,
true);
+ auto queryable = storage.MakeQueryable();
// Filter.
Constraint c{0, FilterOp::kNe, SqlValue::Long(5)};
- QueryExecutor exec({&storage}, 10);
+ QueryExecutor exec({queryable.get()}, 10);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 9u);
@@ -448,10 +482,11 @@
TEST(QueryExecutor, IdSearchIsNull) {
IdStorage storage(5);
+ auto queryable = storage.MakeQueryable();
// Filter.
Constraint c{0, FilterOp::kIsNull, SqlValue()};
- QueryExecutor exec({&storage}, 5);
+ QueryExecutor exec({queryable.get()}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 0u);
@@ -459,10 +494,11 @@
TEST(QueryExecutor, IdSearchIsNotNull) {
IdStorage storage(5);
+ auto queryable = storage.MakeQueryable();
// Filter.
Constraint c{0, FilterOp::kIsNotNull, SqlValue()};
- QueryExecutor exec({&storage}, 5);
+ QueryExecutor exec({queryable.get()}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 5u);
@@ -470,10 +506,11 @@
TEST(QueryExecutor, IdSearchNotEq) {
IdStorage storage(5);
+ auto queryable = storage.MakeQueryable();
// Filter.
Constraint c{0, FilterOp::kNe, SqlValue::Long(3)};
- QueryExecutor exec({&storage}, 5);
+ QueryExecutor exec({queryable.get()}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 4u);
@@ -492,11 +529,12 @@
// Final vec {"cheese", "pasta", "NULL", "pierogi", "fries"}.
BitVector selector_bv{1, 1, 0, 1, 1, 0, 1};
- SelectorOverlay storage(std::move(string), &selector_bv);
+ SelectorOverlay storage(&selector_bv);
+ auto queryable = storage.MakeQueryable(string->MakeQueryable());
// Filter.
Constraint c{0, FilterOp::kIsNull, SqlValue()};
- QueryExecutor exec({&storage}, 5);
+ QueryExecutor exec({queryable.get()}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 1u);
@@ -515,11 +553,12 @@
// Final vec {"apple", "burger", "doughnut", "eggplant"}.
BitVector selector_bv{1, 1, 0, 1, 1, 0};
- SelectorOverlay storage(std::move(string), &selector_bv);
+ SelectorOverlay storage(&selector_bv);
+ auto queryable = storage.MakeQueryable(string->MakeQueryable());
// Filter.
Constraint c{0, FilterOp::kGe, SqlValue::String("camembert")};
- QueryExecutor exec({&storage}, 4);
+ QueryExecutor exec({queryable.get()}, 4);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 2u);
@@ -538,11 +577,12 @@
// Final vec {"apple", "burger", "doughnut", "eggplant"}.
BitVector selector_bv{1, 1, 0, 1, 1, 0};
- SelectorOverlay storage(std::move(string), &selector_bv);
+ SelectorOverlay storage(&selector_bv);
+ auto queryable = storage.MakeQueryable(string->MakeQueryable());
// Filter.
Constraint c{0, FilterOp::kNe, SqlValue::String("doughnut")};
- QueryExecutor exec({&storage}, 4);
+ QueryExecutor exec({queryable.get()}, 4);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 3u);
@@ -551,10 +591,11 @@
TEST(QueryExecutor, MismatchedTypeIdWithString) {
IdStorage storage(5);
+ auto queryable = storage.MakeQueryable();
// Filter.
Constraint c{0, FilterOp::kGe, SqlValue::String("cheese")};
- QueryExecutor exec({&storage}, 5);
+ QueryExecutor exec({queryable.get()}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 0u);
@@ -562,10 +603,11 @@
TEST(QueryExecutor, MismatchedTypeIdWithDouble) {
IdStorage storage(5);
+ auto queryable = storage.MakeQueryable();
// Filter.
Constraint c{0, FilterOp::kGe, SqlValue::Double(1.5)};
- QueryExecutor exec({&storage}, 5);
+ QueryExecutor exec({queryable.get()}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 3u);
@@ -574,10 +616,11 @@
TEST(QueryExecutor, MismatchedTypeSetIdWithDouble) {
std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
SetIdStorage storage(&storage_data);
+ auto queryable = storage.MakeQueryable();
// Filter.
Constraint c{0, FilterOp::kGe, SqlValue::Double(1.5)};
- QueryExecutor exec({&storage}, storage.size());
+ QueryExecutor exec({queryable.get()}, queryable->size());
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 9u);
@@ -597,11 +640,12 @@
// Final vec {"cheese", "pasta", "NULL", "pierogi", "fries"}.
BitVector selector_bv{1, 1, 0, 1, 1, 0, 1};
- SelectorOverlay storage(std::move(string), &selector_bv);
+ SelectorOverlay storage(&selector_bv);
+ auto queryable = storage.MakeQueryable(string->MakeQueryable());
// Filter.
Constraint c{0, FilterOp::kRegex, SqlValue::String("p.*")};
- QueryExecutor exec({&storage}, 5);
+ QueryExecutor exec({queryable.get()}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 2u);
@@ -622,11 +666,12 @@
// Final vec {"cheese", "pasta", "NULL", "pierogi", "fries"}.
BitVector selector_bv{1, 1, 0, 1, 1, 0, 1};
- SelectorOverlay storage(std::move(string), &selector_bv);
+ SelectorOverlay storage(&selector_bv);
+ auto queryable = storage.MakeQueryable(string->MakeQueryable());
// Filter.
Constraint c{0, FilterOp::kRegex, SqlValue::Long(4)};
- QueryExecutor exec({&storage}, 5);
+ QueryExecutor exec({queryable.get()}, 5);
RowMap res = exec.Filter({c});
ASSERT_EQ(res.size(), 0u);
@@ -634,5 +679,4 @@
#endif
} // namespace
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn
index 776b8b2..0d6a3cb 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/android/BUILD.gn
@@ -25,6 +25,7 @@
"broadcasts.sql",
"dvfs.sql",
"garbage_collection.sql",
+ "input.sql",
"io.sql",
"monitor_contention.sql",
"network_packets.sql",
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/input.sql b/src/trace_processor/perfetto_sql/stdlib/android/input.sql
new file mode 100644
index 0000000..f344c20
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/input.sql
@@ -0,0 +1,134 @@
+--
+-- Copyright 2024 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
+--
+-- https://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 PERFETTO MODULE common.timestamps;
+
+CREATE PERFETTO TABLE _input_message_sent
+AS
+SELECT
+ STR_SPLIT(STR_SPLIT(slice.name, '=', 3), ')', 0) AS event_type,
+ STR_SPLIT(STR_SPLIT(slice.name, '=', 2), ',', 0) AS event_seq,
+ STR_SPLIT(STR_SPLIT(slice.name, '=', 1), ',', 0) AS event_channel,
+ thread.tid,
+ thread.name AS thread_name,
+ process.pid,
+ process.name AS process_name,
+ slice.ts,
+ slice.dur,
+ slice.track_id
+FROM slice
+JOIN thread_track
+ ON thread_track.id = slice.track_id
+JOIN thread
+ USING (utid)
+JOIN process
+ USING (upid)
+WHERE slice.name GLOB 'sendMessage(*';
+
+CREATE PERFETTO TABLE _input_message_received
+AS
+SELECT
+ STR_SPLIT(STR_SPLIT(slice.name, '=', 3), ')', 0) AS event_type,
+ STR_SPLIT(STR_SPLIT(slice.name, '=', 2), ',', 0) AS event_seq,
+ STR_SPLIT(STR_SPLIT(slice.name, '=', 1), ',', 0) AS event_channel,
+ thread.tid,
+ thread.name AS thread_name,
+ process.pid,
+ process.name AS process_name,
+ slice.ts,
+ slice.dur,
+ slice.track_id
+FROM slice
+JOIN thread_track
+ ON thread_track.id = slice.track_id
+JOIN thread
+ USING (utid)
+JOIN process
+ USING (upid)
+WHERE slice.name GLOB 'receiveMessage(*';
+
+-- All input events with round trip latency breakdown. Input delivery is socket based and every
+-- input event sent from the OS needs to be ACK'ed by the app. This gives us 4 subevents to measure
+-- latencies between:
+-- 1. Input dispatch event sent from OS.
+-- 2. Input dispatch event received in app.
+-- 3. Input ACK event sent from app.
+-- 4. Input ACk event received in OS.
+CREATE PERFETTO TABLE android_input_events (
+ -- Duration from input dispatch to input received.
+ dispatch_latency_dur INT,
+ -- Duration from input received to input ACK sent.
+ handling_latency_dur INT,
+ -- Duration from input ACK sent to input ACK recieved.
+ ack_latency_dur INT,
+ -- Duration from input dispatch to input event ACK received.
+ total_latency_dur INT,
+ -- Tid of thread receiving the input event.
+ tid INT,
+ -- Name of thread receiving the input event.
+ thread_name INT,
+ -- Pid of process receiving the input event.
+ pid INT,
+ -- Name of process receiving the input event.
+ process_name INT,
+ -- Input event type. See InputTransport.h: InputMessage#Type
+ event_type INT,
+ -- Input event sequence number, monotonically increasing for an event channel and pid.
+ event_seq INT,
+ -- Input event channel name.
+ event_channel INT,
+ -- Thread track id of input event dispatching thread.
+ dispatch_track_id INT,
+ -- Timestamp input event was dispatched.
+ dispatch_ts INT,
+ -- Duration of input event dispatch.
+ dispatch_dur INT,
+ -- Thread track id of input event receiving thread.
+ receive_track_id INT,
+ -- Timestamp input event was received.
+ receive_ts INT,
+ -- Duration of input event receipt.
+ receive_dur INT
+ )
+AS
+SELECT
+ receive.ts - dispatch.ts AS dispatch_latency_dur,
+ finish.ts - receive.ts AS handling_latency_dur,
+ finish_ack.ts - finish.ts AS ack_latency_dur,
+ finish_ack.ts - dispatch.ts AS total_latency_dur,
+ finish.tid AS tid,
+ finish.thread_name AS thread_name,
+ finish.pid AS pid,
+ finish.process_name AS process_name,
+ dispatch.event_type,
+ dispatch.event_seq,
+ dispatch.event_channel,
+ dispatch.track_id AS dispatch_track_id,
+ dispatch.ts AS dispatch_ts,
+ dispatch.dur AS dispatch_dur,
+ receive.ts AS receive_ts,
+ receive.dur AS receive_dur,
+ receive.track_id AS receive_track_id
+FROM (SELECT * FROM _input_message_sent WHERE thread_name = 'InputDispatcher') dispatch
+JOIN (SELECT * FROM _input_message_received WHERE event_type != '0x2') receive
+ ON
+ REPLACE(receive.event_channel, '(client)', '(server)') = dispatch.event_channel
+ AND dispatch.event_seq = receive.event_seq
+JOIN (SELECT * FROM _input_message_sent WHERE thread_name != 'InputDispatcher') finish
+ ON
+ REPLACE(finish.event_channel, '(client)', '(server)') = dispatch.event_channel
+ AND dispatch.event_seq = finish.event_seq
+JOIN (SELECT * FROM _input_message_received WHERE event_type = '0x2') finish_ack
+ ON finish_ack.event_channel = dispatch.event_channel AND dispatch.event_seq = finish_ack.event_seq;
diff --git a/test/data/post_boot_trace.atr.sha256 b/test/data/post_boot_trace.atr.sha256
new file mode 100644
index 0000000..199aa56
--- /dev/null
+++ b/test/data/post_boot_trace.atr.sha256
@@ -0,0 +1 @@
+ed411bb57c771ecff0f04e9eac8dcec3ccafa8c13c82106a4c8f555fe9617fe6
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/stdlib/android/tests.py b/test/trace_processor/diff_tests/stdlib/android/tests.py
index cbd56e4..177174b 100644
--- a/test/trace_processor/diff_tests/stdlib/android/tests.py
+++ b/test/trace_processor/diff_tests/stdlib/android/tests.py
@@ -1088,4 +1088,42 @@
3494,3487,"HeapTaskDaemon","com.android.providers.media.module","young",0,"[NULL]","[NULL]","[NULL]",213263593,55205035,10429437,0,0,1208604
3494,3487,"HeapTaskDaemon","com.android.providers.media.module","collector_transition",0,1.248000,2.201000,3.449000,169735717,65828710,20965673,0,0,0
3556,3549,"HeapTaskDaemon","com.android.externalstorage","collector_transition",0,0.450000,2.038000,2.488000,166379142,52906367,7881722,0,0,0
+ """))
+
+ def test_input_events(self):
+ return DiffTestBlueprint(
+ trace=DataPath('post_boot_trace.atr'),
+ query="""
+ INCLUDE PERFETTO MODULE android.input;
+ SELECT
+ total_latency_dur,
+ handling_latency_dur,
+ dispatch_latency_dur,
+ tid,
+ thread_name,
+ pid,
+ process_name,
+ event_type,
+ event_seq,
+ event_channel,
+ dispatch_ts,
+ dispatch_dur,
+ receive_ts,
+ receive_dur
+ FROM android_input_events
+ ORDER BY dispatch_ts
+ LIMIT 10
+ """,
+ out=Csv("""
+ "total_latency_dur","handling_latency_dur","dispatch_latency_dur","tid","thread_name","pid","process_name","event_type","event_seq","event_channel","dispatch_ts","dispatch_dur","receive_ts","receive_dur"
+ 377149054,77503,377032734,7493,"ndroid.systemui",7493,"com.android.systemui","0x3","0x1","4325794 NotificationShade (server)",578307771330,1292,578684804064,1412
+ 1684318,772908,48433,7493,"ndroid.systemui",7493,"com.android.systemui","0x1","0x2","a0526ca NavigationBar0 (server)",581956322279,1299,581956370712,1806
+ 22069988,12614508,804831,7493,"ndroid.systemui",7493,"com.android.systemui","0x1","0x3","4325794 NotificationShade (server)",581956391308,1212,581957196139,1362
+ 1603522,645723,75328,7964,"droid.launcher3",7964,"com.android.launcher3","0x1","0x4","[Gesture Monitor] swipe-up (server)",581956445376,1232,581956520704,1708
+ 1583707,644313,208973,7310,"android.ui",7288,"system_server","0x1","0x5","PointerEventDispatcher0 (server)",581956495788,1208,581956704761,1281
+ 22622740,22582066,25729,7493,"ndroid.systemui",7493,"com.android.systemui","0x1","0x6","4325794 NotificationShade (server)",582019627670,1230,582019653399,1607
+ 20228399,20116160,95263,7964,"droid.launcher3",7964,"com.android.launcher3","0x1","0x7","[Gesture Monitor] swipe-up (server)",582019685639,1309,582019780902,1942
+ 459763,287436,27342,7310,"android.ui",7288,"system_server","0x1","0x8","PointerEventDispatcher0 (server)",582019737156,1192,582019764498,1664
+ 9848456,9806401,22714,7493,"ndroid.systemui",7493,"com.android.systemui","0x1","0x9","4325794 NotificationShade (server)",582051061377,1227,582051084091,1596
+ 5533919,5487703,25013,7964,"droid.launcher3",7964,"com.android.launcher3","0x1","0xa","[Gesture Monitor] swipe-up (server)",582051112236,1258,582051137249,1771
"""))