Skip to content

Commit f504fae

Browse files
authored
Fix priority queue assertion which enforce the item to have strict order (#14496)
1 parent e07ed04 commit f504fae

File tree

4 files changed

+70
-3
lines changed

4 files changed

+70
-3
lines changed

Firestore/CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Unreleased
2+
- [fixed] Fixed the customized priority queue compare function used cache index manager. (#14496)
3+
14
# 11.9.0
25
- [fixed] Fixed memory leak in `Query.whereField()`. (#13978)
36

Firestore/core/src/local/leveldb_index_manager.cc

+6-1
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,15 @@ LevelDbIndexManager::LevelDbIndexManager(const User& user,
188188
// The contract for this comparison expected by priority queue is
189189
// `std::less`, but std::priority_queue's default order is descending.
190190
// We change the order to be ascending by doing left >= right instead.
191+
// Note: priority queue has to have a strict ordering, so here using unique_id
192+
// to order Field Indexes having same `sequence_number` and `collection_group`
191193
auto cmp = [](FieldIndex* left, FieldIndex* right) {
192194
if (left->index_state().sequence_number() ==
193195
right->index_state().sequence_number()) {
194-
return left->collection_group() >= right->collection_group();
196+
if (left->collection_group() == right->collection_group()) {
197+
return left->unique_id() > right->unique_id();
198+
}
199+
return left->collection_group() > right->collection_group();
195200
}
196201
return left->index_state().sequence_number() >
197202
right->index_state().sequence_number();

Firestore/core/src/model/field_index.cc

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ namespace firebase {
2020
namespace firestore {
2121
namespace model {
2222

23+
std::atomic<int> FieldIndex::ref_count_{0};
24+
2325
util::ComparisonResult Segment::CompareTo(const Segment& rhs) const {
2426
auto result = field_path().CompareTo(rhs.field_path());
2527
if (result != util::ComparisonResult::Same) {

Firestore/core/src/model/field_index.h

+59-2
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,9 @@ class FieldIndex {
243243
static util::ComparisonResult SemanticCompare(const FieldIndex& left,
244244
const FieldIndex& right);
245245

246-
FieldIndex() : index_id_(UnknownId()) {
246+
FieldIndex()
247+
: index_id_(UnknownId()),
248+
unique_id_(ref_count_.fetch_add(1, std::memory_order_acq_rel)) {
247249
}
248250

249251
FieldIndex(int32_t index_id,
@@ -253,7 +255,50 @@ class FieldIndex {
253255
: index_id_(index_id),
254256
collection_group_(std::move(collection_group)),
255257
segments_(std::move(segments)),
256-
state_(std::move(state)) {
258+
state_(std::move(state)),
259+
unique_id_(ref_count_.fetch_add(1, std::memory_order_acq_rel)) {
260+
}
261+
262+
// Copy constructor
263+
FieldIndex(const FieldIndex& other)
264+
: index_id_(other.index_id_),
265+
collection_group_(other.collection_group_),
266+
segments_(other.segments_),
267+
state_(other.state_),
268+
unique_id_(ref_count_.fetch_add(1, std::memory_order_acq_rel)) {
269+
}
270+
271+
// Copy assignment operator
272+
FieldIndex& operator=(const FieldIndex& other) {
273+
if (this != &other) {
274+
index_id_ = other.index_id_;
275+
collection_group_ = other.collection_group_;
276+
segments_ = other.segments_;
277+
state_ = other.state_;
278+
unique_id_ = ref_count_.fetch_add(1, std::memory_order_acq_rel);
279+
}
280+
return *this;
281+
}
282+
283+
// Move constructor
284+
FieldIndex(FieldIndex&& other) noexcept
285+
: index_id_(other.index_id_),
286+
collection_group_(std::move(other.collection_group_)),
287+
segments_(std::move(other.segments_)),
288+
state_(std::move(other.state_)),
289+
unique_id_(ref_count_.fetch_add(1, std::memory_order_acq_rel)) {
290+
}
291+
292+
// Move assignment operator
293+
FieldIndex& operator=(FieldIndex&& other) noexcept {
294+
if (this != &other) {
295+
index_id_ = other.index_id_;
296+
collection_group_ = std::move(other.collection_group_);
297+
segments_ = std::move(other.segments_);
298+
state_ = std::move(other.state_);
299+
unique_id_ = ref_count_.fetch_add(1, std::memory_order_acq_rel);
300+
}
301+
return *this;
257302
}
258303

259304
/**
@@ -285,6 +330,14 @@ class FieldIndex {
285330
/** Returns the ArrayContains/ArrayContainsAny segment for this index. */
286331
absl::optional<Segment> GetArraySegment() const;
287332

333+
/**
334+
* Returns the unique identifier for this object, ensuring a strict ordering
335+
* in the priority queue's comparison function.
336+
*/
337+
int unique_id() const {
338+
return unique_id_;
339+
}
340+
288341
/**
289342
* A type that can be used as the "Compare" template parameter of ordered
290343
* collections to have the elements ordered using
@@ -308,6 +361,10 @@ class FieldIndex {
308361
std::string collection_group_;
309362
std::vector<Segment> segments_;
310363
IndexState state_;
364+
int unique_id_;
365+
366+
// TODO(C++17): Replace with inline static std::atomic<int> ref_count_ = 0;
367+
static std::atomic<int> ref_count_;
311368
};
312369

313370
inline bool operator==(const FieldIndex& lhs, const FieldIndex& rhs) {

0 commit comments

Comments
 (0)