Merge "Add volatile qualifier to AnnotateBenignRaceSized()'s address argument." into main
diff --git a/src/trace_processor/db/BUILD.gn b/src/trace_processor/db/BUILD.gn
index 2cc509f..604929d 100644
--- a/src/trace_processor/db/BUILD.gn
+++ b/src/trace_processor/db/BUILD.gn
@@ -70,6 +70,7 @@
     "../tables",
     "../views",
     "storage",
+    "storage:fake_storage",
   ]
 }
 
diff --git a/src/trace_processor/db/query_executor_unittest.cc b/src/trace_processor/db/query_executor_unittest.cc
index a33b128..e5022c0 100644
--- a/src/trace_processor/db/query_executor_unittest.cc
+++ b/src/trace_processor/db/query_executor_unittest.cc
@@ -17,11 +17,13 @@
 #include "src/trace_processor/db/query_executor.h"
 
 #include "src/trace_processor/db/storage/arrangement_storage.h"
+#include "src/trace_processor/db/storage/fake_storage.h"
 #include "src/trace_processor/db/storage/id_storage.h"
 #include "src/trace_processor/db/storage/null_storage.h"
 #include "src/trace_processor/db/storage/numeric_storage.h"
 #include "src/trace_processor/db/storage/selector_storage.h"
 #include "src/trace_processor/db/storage/set_id_storage.h"
+#include "src/trace_processor/db/storage/storage.h"
 #include "src/trace_processor/db/storage/string_storage.h"
 #include "test/gtest_and_gmock.h"
 
@@ -221,6 +223,34 @@
   ASSERT_THAT(rm.GetAllIndices(), ElementsAre(0u, 4u));
 }
 
+TEST(QueryExecutor, ArrangementOverlaySubsetInputRange) {
+  std::unique_ptr<storage::Storage> fake =
+      storage::FakeStorage::SearchSubset(5u, RowMap::Range(2u, 4u));
+
+  std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
+  storage::ArrangementStorage storage(std::move(fake), &arrangement);
+
+  Constraint c{0, FilterOp::kGe, SqlValue::Long(0u)};
+  RowMap rm(1, 3);
+  QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
+
+  ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u));
+}
+
+TEST(QueryExecutor, ArrangementOverlaySubsetInputBitvector) {
+  std::unique_ptr<storage::Storage> fake =
+      storage::FakeStorage::SearchSubset(5u, BitVector({0, 0, 1, 1, 0}));
+
+  std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
+  storage::ArrangementStorage storage(std::move(fake), &arrangement);
+
+  Constraint c{0, FilterOp::kGe, SqlValue::Long(0u)};
+  RowMap rm(1, 3);
+  QueryExecutor::BoundedColumnFilterForTesting(c, storage, &rm);
+
+  ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u));
+}
+
 TEST(QueryExecutor, ArrangementStorageIndex) {
   std::vector<int64_t> storage_data(5);
   std::iota(storage_data.begin(), storage_data.end(), 0);
@@ -354,7 +384,7 @@
   storage::NullStorage storage(std::move(selector), &null_bv);
 
   // Filter.
-  Constraint c{0, FilterOp::kIsNull, SqlValue::Long(0)};
+  Constraint c{0, FilterOp::kIsNull, SqlValue()};
   QueryExecutor exec({&storage}, 9);
   RowMap res = exec.Filter({c});
 
@@ -378,7 +408,7 @@
   storage::NullStorage storage(std::move(selector), &null_bv);
 
   // Filter.
-  Constraint c{0, FilterOp::kIsNull, SqlValue::Long(0)};
+  Constraint c{0, FilterOp::kIsNull, SqlValue()};
   QueryExecutor exec({&storage}, 10);
   RowMap res = exec.Filter({c});
 
diff --git a/src/trace_processor/db/storage/arrangement_storage.cc b/src/trace_processor/db/storage/arrangement_storage.cc
index 38e6f77..ee777f4 100644
--- a/src/trace_processor/db/storage/arrangement_storage.cc
+++ b/src/trace_processor/db/storage/arrangement_storage.cc
@@ -52,10 +52,10 @@
                           arrangement.begin() + static_cast<int32_t>(in.end));
 
   auto storage_result = inner_->Search(op, sql_val, Range(*min_i, *max_i + 1));
-  BitVector::Builder builder(static_cast<uint32_t>(arrangement.size()));
+  BitVector::Builder builder(in.end, in.start);
   if (storage_result.IsRange()) {
     Range storage_range = std::move(storage_result).TakeIfRange();
-    for (uint32_t i = 0; i < arrangement.size(); ++i) {
+    for (uint32_t i = in.start; i < in.end; ++i) {
       builder.Append(storage_range.Contains(arrangement[i]));
     }
   } else {
diff --git a/src/trace_processor/db/storage/fake_storage.cc b/src/trace_processor/db/storage/fake_storage.cc
index 37474d0..8d2550c 100644
--- a/src/trace_processor/db/storage/fake_storage.cc
+++ b/src/trace_processor/db/storage/fake_storage.cc
@@ -55,16 +55,13 @@
       return RangeOrBitVector(RowMap::Range());
     case kRange:
     case kBitVector: {
-      BitVector bv;
+      BitVector::Builder builder(indices_size);
       for (uint32_t* it = indices; it != indices + indices_size; ++it) {
-        if ((strategy_ == kRange && range_.Contains(*it)) ||
-            (strategy_ == kBitVector && bit_vector_.IsSet(*it))) {
-          bv.AppendTrue();
-        } else {
-          bv.AppendFalse();
-        }
+        bool in_range = strategy_ == kRange && range_.Contains(*it);
+        bool in_bv = strategy_ == kBitVector && bit_vector_.IsSet(*it);
+        builder.Append(in_range || in_bv);
       }
-      return RangeOrBitVector(std::move(bv));
+      return RangeOrBitVector(std::move(builder).Build());
     }
   }
   PERFETTO_FATAL("For GCC");
diff --git a/src/trace_processor/db/storage/id_storage.cc b/src/trace_processor/db/storage/id_storage.cc
index 53e85a8..0493f97 100644
--- a/src/trace_processor/db/storage/id_storage.cc
+++ b/src/trace_processor/db/storage/id_storage.cc
@@ -83,8 +83,9 @@
 
   if (op == FilterOp::kNe) {
     if (sql_val.AsLong() > std::numeric_limits<uint32_t>::max() ||
-        sql_val.AsLong() < std::numeric_limits<uint32_t>::min())
-      return RangeOrBitVector(Range(0, size_));
+        sql_val.AsLong() < std::numeric_limits<uint32_t>::min()) {
+      return RangeOrBitVector(range);
+    }
 
     uint32_t val = static_cast<uint32_t>(sql_val.AsLong());
     BitVector ret(range.start, false);
diff --git a/src/trace_processor/db/storage/id_storage_unittest.cc b/src/trace_processor/db/storage/id_storage_unittest.cc
index 13229e3..57c148d 100644
--- a/src/trace_processor/db/storage/id_storage_unittest.cc
+++ b/src/trace_processor/db/storage/id_storage_unittest.cc
@@ -100,7 +100,7 @@
   IdStorage storage(100);
   Range r = storage.Search(FilterOp::kNe, SqlValue::Long(-1), Range(30, 70))
                 .TakeIfRange();
-  ASSERT_EQ(r.size(), 100u);
+  ASSERT_EQ(r.size(), 40u);
 }
 
 TEST(IdStorageUnittest, Sort) {
diff --git a/src/trace_processor/db/storage/null_storage.cc b/src/trace_processor/db/storage/null_storage.cc
index 7c3920e..cac62d6 100644
--- a/src/trace_processor/db/storage/null_storage.cc
+++ b/src/trace_processor/db/storage/null_storage.cc
@@ -21,6 +21,7 @@
 
 #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/storage/types.h"
 #include "src/trace_processor/tp_metatrace.h"
 
@@ -33,7 +34,10 @@
 
 RangeOrBitVector ReconcileStorageResult(FilterOp op,
                                         const BitVector& non_null,
-                                        RangeOrBitVector storage_result) {
+                                        RangeOrBitVector storage_result,
+                                        Range in_range) {
+  PERFETTO_CHECK(in_range.end <= non_null.size());
+
   // Reconcile the results of the Search operation with the non-null indices
   // to ensure only those positions are set.
   BitVector res;
@@ -42,23 +46,25 @@
     if (range.size() > 0) {
       res = non_null.IntersectRange(non_null.IndexOfNthSet(range.start),
                                     non_null.IndexOfNthSet(range.end - 1) + 1);
+
+      // We should always have at least as many elements as the input range
+      // itself.
+      PERFETTO_CHECK(res.size() <= in_range.end);
     }
   } else {
     res = non_null.Copy();
     res.UpdateSetBits(std::move(storage_result).TakeIfBitVector());
   }
 
-  // Make sure that the reconciled result is *precisely* the size of non_null
-  // vector. This is important as there are assumptions which require that
-  // these sizes match exactly.
-  // TODO(lalitm): consider relaxing this constraint down the line.
-  PERFETTO_DCHECK(res.size() <= non_null.size());
-  res.Resize(non_null.size());
+  // Ensure that |res| exactly matches the size which we need to return,
+  // padding with zeros or truncating if necessary.
+  res.Resize(in_range.end, false);
 
   // For the IS NULL constraint, we also need to include all the null indices
   // themselves.
   if (PERFETTO_UNLIKELY(op == FilterOp::kIsNull)) {
-    BitVector null = non_null.Copy();
+    BitVector null = non_null.IntersectRange(in_range.start, in_range.end);
+    null.Resize(in_range.end, false);
     null.Not();
     res.Or(null);
   }
@@ -83,7 +89,8 @@
   uint32_t start = non_null_->CountSetBits(in.start);
   uint32_t end = non_null_->CountSetBits(in.end);
   return ReconcileStorageResult(
-      op, *non_null_, storage_->Search(op, sql_val, RowMap::Range(start, end)));
+      op, *non_null_, storage_->Search(op, sql_val, RowMap::Range(start, end)),
+      in);
 }
 
 RangeOrBitVector NullStorage::IndexSearch(FilterOp op,
@@ -93,21 +100,21 @@
                                           bool sorted) const {
   PERFETTO_TP_TRACE(metatrace::Category::DB, "NullStorage::IndexSearch");
 
-  BitVector storage_non_null;
+  BitVector::Builder storage_non_null(indices_size);
   std::vector<uint32_t> storage_iv;
   storage_iv.reserve(indices_size);
   for (uint32_t* it = indices; it != indices + indices_size; it++) {
-    if (non_null_->IsSet(*it)) {
+    bool is_non_null = non_null_->IsSet(*it);
+    if (is_non_null) {
       storage_iv.push_back(non_null_->CountSetBits(*it));
-      storage_non_null.AppendTrue();
-    } else {
-      storage_non_null.AppendFalse();
     }
+    storage_non_null.Append(is_non_null);
   }
   RangeOrBitVector range_or_bv =
       storage_->IndexSearch(op, sql_val, storage_iv.data(),
                             static_cast<uint32_t>(storage_iv.size()), sorted);
-  return ReconcileStorageResult(op, storage_non_null, std::move(range_or_bv));
+  return ReconcileStorageResult(op, std::move(storage_non_null).Build(),
+                                std::move(range_or_bv), Range(0, indices_size));
 }
 
 void NullStorage::StableSort(uint32_t*, uint32_t) const {
diff --git a/src/trace_processor/db/storage/null_storage_unittest.cc b/src/trace_processor/db/storage/null_storage_unittest.cc
index a7404ab..daa235f 100644
--- a/src/trace_processor/db/storage/null_storage_unittest.cc
+++ b/src/trace_processor/db/storage/null_storage_unittest.cc
@@ -83,7 +83,7 @@
   NullStorage storage(FakeStorage::SearchSubset(4u, BitVector{0, 1, 0, 1}),
                       &bv);
 
-  auto res = storage.Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 11));
+  auto res = storage.Search(FilterOp::kGt, SqlValue::Long(0), Range(0, 8));
   ASSERT_THAT(ToIndexVector(res), ElementsAre(2, 6));
 }
 
@@ -92,7 +92,7 @@
   NullStorage storage(FakeStorage::SearchSubset(4u, BitVector{0, 1, 0, 1}),
                       &bv);
 
-  auto res = storage.Search(FilterOp::kIsNull, SqlValue(), Range(0, 11));
+  auto res = storage.Search(FilterOp::kIsNull, SqlValue(), Range(0, 8));
   ASSERT_THAT(ToIndexVector(res), ElementsAre(0, 2, 3, 4, 6, 7));
 }
 
diff --git a/src/trace_processor/db/storage/numeric_storage.cc b/src/trace_processor/db/storage/numeric_storage.cc
index 184b1e1..b7ecfa9 100644
--- a/src/trace_processor/db/storage/numeric_storage.cc
+++ b/src/trace_processor/db/storage/numeric_storage.cc
@@ -220,11 +220,10 @@
     // range, and rather just `not` range returned with `equal` operation.
     RowMap::Range r = BinarySearchIntrinsic(FilterOp::kEq, value, range);
     BitVector bv(r.start, true);
-    bv.Resize(r.end);
+    bv.Resize(r.end, false);
     bv.Resize(range.end, true);
     return RangeOrBitVector(std::move(bv));
   }
-
   return RangeOrBitVector(LinearSearchInternal(op, value, range));
 }
 
@@ -252,10 +251,10 @@
                                                    RowMap::Range range) const {
   std::optional<NumericValue> val = GetNumericTypeVariant(type_, sql_val);
   if (op == FilterOp::kIsNotNull)
-    return BitVector(size(), true);
+    return BitVector(range.end, true);
 
   if (!val.has_value() || op == FilterOp::kIsNull || op == FilterOp::kGlob)
-    return BitVector(size(), false);
+    return BitVector(range.end, false);
 
   BitVector::Builder builder(range.end, range.start);
   if (const auto* u32 = std::get_if<uint32_t>(&*val)) {
@@ -428,7 +427,7 @@
       PERFETTO_FATAL("Invalid column type for NumericStorage");
   }
   numeric_storage_msg->set_values(static_cast<const uint8_t*>(data_),
-                                  static_cast<size_t>(type_size * size_));
+                                  static_cast<size_t>(type_size) * size_);
 }
 
 }  // namespace storage
diff --git a/src/trace_processor/db/storage/set_id_storage.cc b/src/trace_processor/db/storage/set_id_storage.cc
index 76c7982..8244ae0 100644
--- a/src/trace_processor/db/storage/set_id_storage.cc
+++ b/src/trace_processor/db/storage/set_id_storage.cc
@@ -79,9 +79,10 @@
     // range, and rather just `not` range returned with `equal` operation.
     RowMap::Range eq_range =
         BinarySearchIntrinsic(FilterOp::kEq, sql_val, range);
-    BitVector bv(eq_range.start, true);
-    bv.Resize(eq_range.end);
-    bv.Resize(std::min(range.end - 1, eq_range.end), true);
+    BitVector bv(range.start, false);
+    bv.Resize(eq_range.start, true);
+    bv.Resize(eq_range.end, false);
+    bv.Resize(range.end, true);
     return RangeOrBitVector(std::move(bv));
   }
   return RangeOrBitVector(BinarySearchIntrinsic(op, sql_val, range));
diff --git a/src/trace_processor/db/storage/storage.h b/src/trace_processor/db/storage/storage.h
index 989423c..605329b 100644
--- a/src/trace_processor/db/storage/storage.h
+++ b/src/trace_processor/db/storage/storage.h
@@ -38,14 +38,37 @@
 
   // 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 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 op,
                                   SqlValue value,
                                   RowMap::Range range) const = 0;
 
   // Searches for elements which match |op| and |value| at the positions given
-  // by |indices| array.
-  // If the order defined by |indices| makes storage sorted, |sorted| flag
-  // should be set to true.
+  // by |indices| array. The |sorted| flag allows the caller to specify if the
+  // order defined by |indices| makes storage sorted; implementations can use
+  // this to optimize how they search the storage.
+  //
+  // 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:
+  //  * 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 op,
                                        SqlValue value,
                                        uint32_t* indices,
diff --git a/src/trace_processor/db/storage/string_storage.cc b/src/trace_processor/db/storage/string_storage.cc
index 0ba5f00..d1d88b7 100644
--- a/src/trace_processor/db/storage/string_storage.cc
+++ b/src/trace_processor/db/storage/string_storage.cc
@@ -182,7 +182,7 @@
     // a range, and rather just `not` range returned with `equal` operation.
     RowMap::Range r = BinarySearchIntrinsic(FilterOp::kEq, value, range);
     BitVector bv(r.start, true);
-    bv.Resize(r.end);
+    bv.Resize(r.end, false);
     bv.Resize(range.end, true);
     return RangeOrBitVector(std::move(bv));
   }
@@ -214,12 +214,12 @@
                                               RowMap::Range range) const {
   if (sql_val.is_null() &&
       (op != FilterOp::kIsNotNull && op != FilterOp::kIsNull)) {
-    return BitVector();
+    return BitVector(range.end, false);
   }
 
   if (sql_val.type != SqlValue::kString &&
       (op == FilterOp::kGlob || op == FilterOp::kRegex)) {
-    return BitVector();
+    return BitVector(range.end, false);
   }
 
   StringPool::Id val =