diff options
author | Dan Larkin-York <dan.larkin-york@mongodb.com> | 2021-03-04 22:04:44 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-03-05 19:15:45 +0000 |
commit | 7676194fd8a363c7c9f3099e814dc71bbe401efb (patch) | |
tree | 65b8feff9e39c7a02b19a66e4a8c6d5651eed267 | |
parent | 36597e8ce4fcf00e777bca348929c1530a79c699 (diff) | |
download | mongo-7676194fd8a363c7c9f3099e814dc71bbe401efb.tar.gz |
SERVER-54922 Fix broken promises resulting from concurrency issue in BucketCatalog::clear
-rw-r--r-- | src/mongo/db/timeseries/bucket_catalog.cpp | 26 | ||||
-rw-r--r-- | src/mongo/db/timeseries/bucket_catalog.h | 1 |
2 files changed, 19 insertions, 8 deletions
diff --git a/src/mongo/db/timeseries/bucket_catalog.cpp b/src/mongo/db/timeseries/bucket_catalog.cpp index 06a9c71985d..b5b01b68631 100644 --- a/src/mongo/db/timeseries/bucket_catalog.cpp +++ b/src/mongo/db/timeseries/bucket_catalog.cpp @@ -320,17 +320,23 @@ void BucketCatalog::clear(const BucketId& bucketId) { return; } - while (!bucket->promises.empty()) { - if (auto& promise = bucket->promises.front()) { - promise->setError({ErrorCodes::TimeseriesBucketCleared, - str::stream() << "Time-series bucket " << *bucketId << " for " - << bucket->ns << " was cleared"}); + // Retain pointer to bucket, release so we can get an exclusive lock. + std::shared_ptr<Bucket> underlyingBucket{bucket}; + bucket.release(); + auto lk = _lockExclusive(); + + { + stdx::lock_guard blk{underlyingBucket->lock}; + while (!underlyingBucket->promises.empty()) { + if (auto& promise = underlyingBucket->promises.front()) { + promise->setError({ErrorCodes::TimeseriesBucketCleared, + str::stream() << "Time-series bucket " << *bucketId << " for " + << underlyingBucket->ns << " was cleared"}); + } + underlyingBucket->promises.pop(); } - bucket->promises.pop(); } - bucket.release(); - auto lk = _lockExclusive(); _removeBucket(bucketId); } @@ -652,6 +658,10 @@ BucketCatalog::BucketAccess::operator bool() const { return isLocked(); } +BucketCatalog::BucketAccess::operator std::shared_ptr<BucketCatalog::Bucket>() const { + return _bucket; +} + void BucketCatalog::BucketAccess::rollover(const std::function<bool(BucketAccess*)>& isBucketFull) { invariant(isLocked()); invariant(_key); diff --git a/src/mongo/db/timeseries/bucket_catalog.h b/src/mongo/db/timeseries/bucket_catalog.h index ad7e5740d48..66f8d493cc8 100644 --- a/src/mongo/db/timeseries/bucket_catalog.h +++ b/src/mongo/db/timeseries/bucket_catalog.h @@ -388,6 +388,7 @@ private: bool isLocked() const; Bucket* operator->(); operator bool() const; + operator std::shared_ptr<Bucket>() const; // Release the bucket lock, typically in order to reacquire the catalog lock. void release(); |