Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firestore: Fix memory leak in Query.whereField() #14300

Open
wants to merge 104 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
769e1df
Firestore: Fix memory leak in thread_safe_memoizer.h
dconeybe Jan 3, 2025
110c0f0
Firestore/CHANGELOG.md updated
dconeybe Jan 3, 2025
0e8bc9d
use absl::make_unique instead of std::make_unique
dconeybe Jan 3, 2025
260de9f
upgrade python from 3.7 to 3.11 in firestore.yml and firestore-nightl…
dconeybe Jan 3, 2025
3451e13
firestore.yml: add workflow_dispatch trigger
dconeybe Jan 3, 2025
8df7855
Merge remote-tracking branch 'origin/main' into ThreadSafeMemoizerMem…
dconeybe Jan 4, 2025
ab5bc69
thread_safe_memoizer.h: add missing #include <atomic>
dconeybe Jan 5, 2025
7d9f957
string_format.h: create the StringifySink at the correct scope and pa…
dconeybe Jan 6, 2025
1f00fb1
string_format.h: format code
dconeybe Jan 6, 2025
0f7dd55
Merge remote-tracking branch 'origin/main' into ThreadSafeMemoizerMem…
dconeybe Jan 6, 2025
aeb0b05
string_format.h: fix use-after-free bug due to insufficient lifetime …
dconeybe Jan 6, 2025
82e5289
string_format_test.cc: strengthen Pointer test to match a regex rathe…
dconeybe Jan 6, 2025
24066f5
Firestore/CHANGELOG.md entry added
dconeybe Jan 6, 2025
a4ef6c6
Merge branch 'StringFormatStringifySinkUseAfterFreeFix' into ThreadSa…
dconeybe Jan 6, 2025
2a30d70
use std::shared_ptr to much more easily implement the shared ownershi…
dconeybe Jan 6, 2025
f5ae906
remove the comment about making thread_safe_memoizer.h copyable
dconeybe Jan 6, 2025
d925a22
thread_safe_memoizer.h reword
dconeybe Jan 7, 2025
903df59
get things to compile
dconeybe Jan 7, 2025
514ce75
Merge remote-tracking branch 'origin/main' into ThreadSafeMemoizerMem…
dconeybe Jan 7, 2025
d21fb17
minor code cleanup
dconeybe Jan 7, 2025
2ca4d15
more cleanup;
dconeybe Jan 7, 2025
bc0f5c9
add missing include
dconeybe Jan 7, 2025
90a3564
thread_safe_memoizer.h: use std::atomic<std::shared_ptr>> in c++20
dconeybe Jan 7, 2025
23e4cf5
Merge remote-tracking branch 'origin/main' into ThreadSafeMemoizerMem…
dconeybe Jan 7, 2025
f3aa1b6
Merge remote-tracking branch 'origin/main' into StringFormatStringify…
dconeybe Jan 7, 2025
b9592b3
Merge branch 'StringFormatStringifySinkUseAfterFreeFix' into ThreadSa…
dconeybe Jan 7, 2025
c376080
fix lint
dconeybe Jan 7, 2025
d344f17
thread_safe_memoizer_test.cc: starting rewrite
dconeybe Jan 8, 2025
ca8fb41
Firestore/core/test/unit/util/thread_safe_memoizer_testing_test.cc added
dconeybe Jan 8, 2025
7313213
fix regex tests
dconeybe Jan 8, 2025
5833e22
cleanups
dconeybe Jan 8, 2025
2c232f5
thread_safe_memoizer_test.cc: Value_ShouldNotInvokeTheFunctionAfterMe…
dconeybe Jan 8, 2025
e6c26a7
thread_safe_memoizer_test.cc: copy constructor tests
dconeybe Jan 8, 2025
76f3249
thread_safe_memoizer_test.cc: move constructor tests
dconeybe Jan 8, 2025
32025e7
thread_safe_memoizer_test.cc: copy assignment operator tests
dconeybe Jan 8, 2025
ccc3b3b
thread_safe_memoizer_test.cc: move assignment operator tests
dconeybe Jan 8, 2025
05b074c
thread_safe_memoizer_test.cc: add tests to make sure the object gets …
dconeybe Jan 8, 2025
a37a376
Firestore.xcodeproj/project.pbxproj: add missing files
dconeybe Jan 8, 2025
901b7b5
cpplint.py: remove c++11 lint checks, as the floor is c++14 (and has …
dconeybe Jan 8, 2025
b55ee13
cpplint.py: remove c++11 lint checks, as the floor is c++14 (and has …
dconeybe Jan 8, 2025
b84c9b6
thread_safe_memoizer_testing.cc: add missing #include <utility>
dconeybe Jan 8, 2025
c46f9d2
also remove cpp14 warnings
dconeybe Jan 8, 2025
aebe23e
also remove c++14 warnings
dconeybe Jan 8, 2025
3b2583c
Merge remote-tracking branch 'origin/main' into StringFormatStringify…
dconeybe Jan 9, 2025
64d14b8
string_format_test.cc: improve robustness of NonNullPointer test to a…
dconeybe Jan 9, 2025
da3f7c9
Merge remote-tracking branch 'origin/main' into StringFormatStringify…
dconeybe Jan 9, 2025
1721117
string_format.h: make FormatArg final, to strongly discourage others …
dconeybe Jan 9, 2025
72833ca
add comment about b/388888512
dconeybe Jan 9, 2025
68ccc04
format code
dconeybe Jan 9, 2025
7464449
Merge remote-tracking branch 'remotes/origin/dconeybe/StringFormatStr…
dconeybe Jan 9, 2025
ef59e2c
Merge remote-tracking branch 'origin/main' into ThreadSafeMemoizerMem…
dconeybe Jan 10, 2025
012b8a9
fix lint
dconeybe Jan 10, 2025
7800770
Merge remote-tracking branch 'origin/main' into RemoveCpp11LintChecks
dconeybe Jan 10, 2025
e3aa90f
cpplint.py: actually remove the c++11 and C++14 checks.
dconeybe Jan 10, 2025
e2031c7
cpplint.py: remove usages of the deprecated sre_compile Python module.
dconeybe Jan 10, 2025
73e74cf
cpplint.py: relax checks for "using namespace" declarations for impor…
dconeybe Jan 10, 2025
bb3b0f3
.github/workflows/firestore.yml: run Firestore tests when cpplint.py …
dconeybe Jan 10, 2025
0b737db
Revert ".github/workflows/firestore.yml: run Firestore tests when cpp…
dconeybe Jan 10, 2025
fb7df47
scripts/check.sh: run lint on _ALL_ files if cpplint.py itself changed.
dconeybe Jan 10, 2025
bd0a6d8
scripts/check.sh: fix check of base branch
dconeybe Jan 10, 2025
7435976
scripts/check.sh: more fixes
dconeybe Jan 10, 2025
1685499
scripts/check.sh: try again
dconeybe Jan 10, 2025
a1bf8c0
scripts/check.sh: also check for changes to cpplint.py
dconeybe Jan 10, 2025
39318ff
Merge remote-tracking branch 'remotes/origin/dconeybe/RemoveCpp11Lint…
dconeybe Jan 10, 2025
55c2437
thread_safe_memoizer.h: add comments explaining the rationale for usi…
dconeybe Jan 10, 2025
694533f
.github/workflows/firestore.yml: run tests under C++20 as well
dconeybe Jan 10, 2025
954e171
.github/workflows/firestore.yml: grep for CMAKE_CXX_STANDARD to provi…
dconeybe Jan 10, 2025
98dfa26
.github/workflows/firestore.yml: improve output when patching c++ ver…
dconeybe Jan 10, 2025
2d43959
fix some c++20 build errors
dconeybe Jan 10, 2025
57d60cf
.github/workflows/firestore.yml: run tests with c++17, in addition to…
dconeybe Jan 10, 2025
713ae35
utf8_testing.h: remove constexpr from StringFromU8String return type,…
dconeybe Jan 10, 2025
cd059dc
.github/workflows/firestore.yml: run on c++17 and c++23, as well as w…
dconeybe Jan 10, 2025
dbc6832
format code
dconeybe Jan 10, 2025
899a256
utf8_testing.h: fix copyright header
dconeybe Jan 10, 2025
dbb11b7
.github/workflows/firestore.yml: fix `env` completing with non-zero e…
dconeybe Jan 10, 2025
83ba2fc
fix some warnings: explicit capture of 'this' with a capture default …
dconeybe Jan 10, 2025
472ee58
format code
dconeybe Jan 10, 2025
c66acf7
Merge remote-tracking branch 'origin/main' into ThreadSafeMemoizerMem…
dconeybe Jan 10, 2025
dabc396
.github/workflows/firestore.yml: remove testing in c++23, since it is…
dconeybe Jan 10, 2025
b3366bf
cmake/compiler_setup.cmake: clean up warnings to be more practical
dconeybe Jan 10, 2025
10ebc75
cmake/compiler_setup.cmake: disable redundant-move altogether
dconeybe Jan 10, 2025
4608f23
thread_safe_memoizer.h: fix data race
dconeybe Jan 10, 2025
b386b40
thread_safe_memoizer_test.cc: add TSAN-specific tests: TSAN_Concurren…
dconeybe Jan 10, 2025
686db4c
lru_garbage_collector.cc: fix c++20 build error relating to inconsist…
dconeybe Jan 10, 2025
03cf713
direction.cc/testutil.cc: fix c++20 build error relating to inconsist…
dconeybe Jan 10, 2025
e4241e4
cpplint.py: add back error categories: build/c++11, build/c++14, buil…
dconeybe Jan 10, 2025
4c80660
Merge remote-tracking branch 'origin/main' into RemoveCpp11LintChecks
dconeybe Jan 10, 2025
167b427
cpplint.py: add back error categories: build/c++11, build/c++14, buil…
dconeybe Jan 10, 2025
e66e4c7
Merge remote-tracking branch 'remotes/origin/dconeybe/RemoveCpp11Lint…
dconeybe Jan 10, 2025
a87d159
git checkout --no-overlay origin/main .
dconeybe Jan 13, 2025
7f05f8d
thread_safe_memoizer.h: re-write using atomics to fix apparent memory…
dconeybe Jan 13, 2025
634a47a
Firestore/Example/Firestore.xcodeproj/project.pbxproj updated
dconeybe Jan 13, 2025
8f65488
scripts/cpplint.py: remove warnings about using std::make_unique() si…
dconeybe Jan 13, 2025
11b5324
fix lint
dconeybe Jan 13, 2025
48563d7
Merge remote-tracking branch 'origin/main' into ThreadSafeMemoizerMem…
dconeybe Jan 13, 2025
a209bd4
scripts/check.sh: remove my changes since I'm not entirely convinced …
dconeybe Jan 13, 2025
d2f0c10
Merge remote-tracking branch 'origin/main' into RemoveCpp11LintChecks
dconeybe Jan 13, 2025
6a5c600
scripts/cpplint.py: add back build/namespaces_literals so that cpplin…
dconeybe Jan 13, 2025
7607f94
Merge branch 'RemoveCpp11LintChecks' into ThreadSafeMemoizerMemoryLea…
dconeybe Jan 13, 2025
f6e95a3
scripts/cpplint.py: undo local changes
dconeybe Jan 13, 2025
605bcf4
Revert "fix lint"
dconeybe Jan 13, 2025
342557b
Merge remote-tracking branch 'origin/main' into ThreadSafeMemoizerMem…
dconeybe Jan 14, 2025
fae4442
thread_safe_memoizer.h: tighten determinism of value() to call the gi…
dconeybe Jan 14, 2025
8f5d1e9
fix when running under tsan
dconeybe Jan 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Firestore/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Unreleased
- [fixed] Fixed memory leak in `Query.whereField()`. (#13978)
- [fixed] Fixed use-after-free bug when internally formatting strings. (#14306)

# 11.6.0
Expand Down
30 changes: 30 additions & 0 deletions Firestore/Example/Firestore.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

19 changes: 9 additions & 10 deletions Firestore/core/src/core/composite_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "Firestore/core/src/core/composite_filter.h"

#include <algorithm>
#include <memory>
#include <utility>

#include "Firestore/core/src/core/field_filter.h"
Expand Down Expand Up @@ -141,16 +142,14 @@ const FieldFilter* CompositeFilter::Rep::FindFirstMatchingFilter(
return nullptr;
}

const std::vector<FieldFilter>& CompositeFilter::Rep::GetFlattenedFilters()
const {
return memoized_flattened_filters_->memoize([&]() {
std::vector<FieldFilter> flattened_filters;
for (const auto& filter : filters())
std::copy(filter.GetFlattenedFilters().begin(),
filter.GetFlattenedFilters().end(),
std::back_inserter(flattened_filters));
return flattened_filters;
});
std::shared_ptr<std::vector<FieldFilter>>
CompositeFilter::Rep::CalculateFlattenedFilters() const {
auto flattened_filters = std::make_shared<std::vector<FieldFilter>>();
for (const auto& filter : filters())
std::copy(filter.GetFlattenedFilters().begin(),
filter.GetFlattenedFilters().end(),
std::back_inserter(*flattened_filters));
return flattened_filters;
}

} // namespace core
Expand Down
3 changes: 2 additions & 1 deletion Firestore/core/src/core/composite_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ class CompositeFilter : public Filter {
return filters_.empty();
}

const std::vector<FieldFilter>& GetFlattenedFilters() const override;
std::shared_ptr<std::vector<FieldFilter>> CalculateFlattenedFilters()
const override;

std::vector<Filter> GetFilters() const override {
return filters();
Expand Down
11 changes: 6 additions & 5 deletions Firestore/core/src/core/field_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "Firestore/core/src/core/field_filter.h"

#include <memory>
#include <utility>

#include "Firestore/core/src/core/array_contains_any_filter.h"
Expand Down Expand Up @@ -122,12 +123,12 @@ FieldFilter::FieldFilter(std::shared_ptr<const Filter::Rep> rep)
: Filter(std::move(rep)) {
}

const std::vector<FieldFilter>& FieldFilter::Rep::GetFlattenedFilters() const {
std::shared_ptr<std::vector<FieldFilter>>
FieldFilter::Rep::CalculateFlattenedFilters() const {
// This is already a field filter, so we return a vector of size one.
return memoized_flattened_filters_->memoize([&]() {
return std::vector<FieldFilter>{
FieldFilter(std::make_shared<const Rep>(*this))};
});
auto filters = std::make_shared<std::vector<FieldFilter>>();
filters->push_back(FieldFilter(std::make_shared<const Rep>(*this)));
return filters;
}

std::vector<Filter> FieldFilter::Rep::GetFilters() const {
Expand Down
5 changes: 3 additions & 2 deletions Firestore/core/src/core/field_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,6 @@ class FieldFilter : public Filter {
return false;
}

const std::vector<FieldFilter>& GetFlattenedFilters() const override;

std::vector<Filter> GetFilters() const override;

protected:
Expand All @@ -140,6 +138,9 @@ class FieldFilter : public Filter {

bool MatchesComparison(util::ComparisonResult comparison) const;

std::shared_ptr<std::vector<FieldFilter>> CalculateFlattenedFilters()
const override;

private:
friend class FieldFilter;

Expand Down
6 changes: 0 additions & 6 deletions Firestore/core/src/core/filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@ std::ostream& operator<<(std::ostream& os, const Filter& filter) {
return os << filter.ToString();
}

Filter::Rep::Rep()
: memoized_flattened_filters_(
std::make_shared<
util::ThreadSafeMemoizer<std::vector<FieldFilter>>>()) {
}

} // namespace core
} // namespace firestore
} // namespace firebase
20 changes: 12 additions & 8 deletions Firestore/core/src/core/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef FIRESTORE_CORE_SRC_CORE_FILTER_H_
#define FIRESTORE_CORE_SRC_CORE_FILTER_H_

#include <functional>
#include <iosfwd>
#include <memory>
#include <string>
Expand Down Expand Up @@ -114,7 +115,7 @@ class Filter {
protected:
class Rep {
public:
Rep();
Rep() = default;

virtual ~Rep() = default;

Expand Down Expand Up @@ -147,20 +148,23 @@ class Filter {

virtual bool IsEmpty() const = 0;

virtual const std::vector<FieldFilter>& GetFlattenedFilters() const = 0;
virtual const std::vector<FieldFilter>& GetFlattenedFilters() const {
const auto func = std::bind(&Rep::CalculateFlattenedFilters, this);
return memoized_flattened_filters_.value(func);
}

virtual std::vector<Filter> GetFilters() const = 0;

protected:
virtual std::shared_ptr<std::vector<FieldFilter>>
CalculateFlattenedFilters() const = 0;

private:
/**
* Memoized list of all field filters that can be found by
* traversing the tree of filters contained in this composite filter.
*
* Use a `std::shared_ptr<ThreadSafeMemoizer>` rather than using
* `ThreadSafeMemoizer` directly so that this class is copyable
* (`ThreadSafeMemoizer` is not copyable because of its `std::once_flag`
* member variable, which is not copyable).
*/
mutable std::shared_ptr<util::ThreadSafeMemoizer<std::vector<FieldFilter>>>
mutable util::ThreadSafeMemoizer<std::vector<FieldFilter>>
memoized_flattened_filters_;
};

Expand Down
77 changes: 37 additions & 40 deletions Firestore/core/src/core/query.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "Firestore/core/src/core/query.h"

#include <algorithm>
#include <memory>
#include <ostream>

#include "Firestore/core/src/core/bound.h"
Expand Down Expand Up @@ -91,44 +92,42 @@ absl::optional<Operator> Query::FindOpInsideFilters(
return absl::nullopt;
}

const std::vector<OrderBy>& Query::normalized_order_bys() const {
return memoized_normalized_order_bys_->memoize([&]() {
// Any explicit order by fields should be added as is.
std::vector<OrderBy> result = explicit_order_bys_;
std::set<FieldPath> fieldsNormalized;
for (const OrderBy& order_by : explicit_order_bys_) {
fieldsNormalized.insert(order_by.field());
}
std::shared_ptr<std::vector<OrderBy>> Query::CalculateNormalizedOrderBys()
const {
// Any explicit order by fields should be added as is.
auto result = std::make_shared<std::vector<OrderBy>>(explicit_order_bys_);
std::set<FieldPath> fieldsNormalized;
for (const OrderBy& order_by : explicit_order_bys_) {
fieldsNormalized.insert(order_by.field());
}

// The order of the implicit ordering always matches the last explicit order
// by.
Direction last_direction = explicit_order_bys_.empty()
? Direction::Ascending
: explicit_order_bys_.back().direction();

// Any inequality fields not explicitly ordered should be implicitly ordered
// in a lexicographical order. When there are multiple inequality filters on
// the same field, the field should be added only once. Note:
// `std::set<model::FieldPath>` sorts the key field before other fields.
// However, we want the key field to be sorted last.
const std::set<model::FieldPath> inequality_fields =
InequalityFilterFields();

for (const model::FieldPath& field : inequality_fields) {
if (fieldsNormalized.find(field) == fieldsNormalized.end() &&
!field.IsKeyFieldPath()) {
result.push_back(OrderBy(field, last_direction));
}
// The order of the implicit ordering always matches the last explicit order
// by.
Direction last_direction = explicit_order_bys_.empty()
? Direction::Ascending
: explicit_order_bys_.back().direction();

// Any inequality fields not explicitly ordered should be implicitly ordered
// in a lexicographical order. When there are multiple inequality filters on
// the same field, the field should be added only once. Note:
// `std::set<model::FieldPath>` sorts the key field before other fields.
// However, we want the key field to be sorted last.
const std::set<model::FieldPath> inequality_fields = InequalityFilterFields();

for (const model::FieldPath& field : inequality_fields) {
if (fieldsNormalized.find(field) == fieldsNormalized.end() &&
!field.IsKeyFieldPath()) {
result->push_back(OrderBy(field, last_direction));
}
}

// Add the document key field to the last if it is not explicitly ordered.
if (fieldsNormalized.find(FieldPath::KeyFieldPath()) ==
fieldsNormalized.end()) {
result.push_back(OrderBy(FieldPath::KeyFieldPath(), last_direction));
}
// Add the document key field to the last if it is not explicitly ordered.
if (fieldsNormalized.find(FieldPath::KeyFieldPath()) ==
fieldsNormalized.end()) {
result->push_back(OrderBy(FieldPath::KeyFieldPath(), last_direction));
}

return result;
});
return result;
}

LimitType Query::limit_type() const {
Expand Down Expand Up @@ -296,14 +295,12 @@ std::string Query::ToString() const {
return absl::StrCat("Query(canonical_id=", CanonicalId(), ")");
}

const Target& Query::ToTarget() const& {
return memoized_target_->memoize(
[&]() { return ToTarget(normalized_order_bys()); });
std::shared_ptr<Target> Query::CalculateTarget() const {
return std::make_shared<Target>(ToTarget(normalized_order_bys()));
}

const Target& Query::ToAggregateTarget() const& {
return memoized_aggregate_target_->memoize(
[&]() { return ToTarget(explicit_order_bys_); });
std::shared_ptr<Target> Query::CalculateAggregateTarget() const {
return std::make_shared<Target>(ToTarget(explicit_order_bys_));
}

Target Query::ToTarget(const std::vector<OrderBy>& order_bys) const {
Expand Down
31 changes: 20 additions & 11 deletions Firestore/core/src/core/query.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef FIRESTORE_CORE_SRC_CORE_QUERY_H_
#define FIRESTORE_CORE_SRC_CORE_QUERY_H_

#include <functional>
#include <iosfwd>
#include <limits>
#include <memory>
Expand Down Expand Up @@ -148,7 +149,10 @@ class Query {
* This might include additional sort orders added implicitly to match the
* backend behavior.
*/
const std::vector<OrderBy>& normalized_order_bys() const;
const std::vector<OrderBy>& normalized_order_bys() const {
const auto func = std::bind(&Query::CalculateNormalizedOrderBys, this);
return memoized_normalized_order_bys_.value(func);
}

bool has_limit() const {
return limit_ != Target::kNoLimit;
Expand Down Expand Up @@ -246,15 +250,21 @@ class Query {
* Returns a `Target` instance this query will be mapped to in backend
* and local store.
*/
const Target& ToTarget() const&;
const Target& ToTarget() const& {
const auto func = std::bind(&Query::CalculateTarget, this);
return memoized_target_.value(func);
}

/**
* Returns a `Target` instance this query will be mapped to in backend
* and local store, for use within an aggregate query. Unlike targets
* for non-aggregate queries, aggregate query targets do not contain
* normalized order-bys, they only contain explicit order-bys.
*/
const Target& ToAggregateTarget() const&;
const Target& ToAggregateTarget() const& {
const auto func = std::bind(&Query::CalculateAggregateTarget, this);
return memoized_aggregate_target_.value(func);
}

friend std::ostream& operator<<(std::ostream& os, const Query& query);

Expand Down Expand Up @@ -295,20 +305,19 @@ class Query {
// member variable, which is not copyable).

// The memoized list of sort orders.
mutable std::shared_ptr<util::ThreadSafeMemoizer<std::vector<OrderBy>>>
memoized_normalized_order_bys_{
std::make_shared<util::ThreadSafeMemoizer<std::vector<OrderBy>>>()};
std::shared_ptr<std::vector<OrderBy>> CalculateNormalizedOrderBys() const;
mutable util::ThreadSafeMemoizer<std::vector<OrderBy>>
memoized_normalized_order_bys_;

// The corresponding Target of this Query instance.
mutable std::shared_ptr<util::ThreadSafeMemoizer<Target>> memoized_target_{
std::make_shared<util::ThreadSafeMemoizer<Target>>()};
std::shared_ptr<Target> CalculateTarget() const;
mutable util::ThreadSafeMemoizer<Target> memoized_target_;

// The corresponding aggregate Target of this Query instance. Unlike targets
// for non-aggregate queries, aggregate query targets do not contain
// normalized order-bys, they only contain explicit order-bys.
mutable std::shared_ptr<util::ThreadSafeMemoizer<Target>>
memoized_aggregate_target_{
std::make_shared<util::ThreadSafeMemoizer<Target>>()};
std::shared_ptr<Target> CalculateAggregateTarget() const;
mutable util::ThreadSafeMemoizer<Target> memoized_aggregate_target_;
};

bool operator==(const Query& lhs, const Query& rhs);
Expand Down
Loading
Loading