multi_resource_lock.h 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. #pragma once
  2. #include "yql_panic.h"
  3. #include <util/generic/map.h>
  4. #include <util/generic/ptr.h>
  5. #include <util/generic/string.h>
  6. #include <util/system/mutex.h>
  7. namespace NYql {
  8. class TMultiResourceLock : private TNonCopyable {
  9. private:
  10. struct TLock : public TThrRefBase {
  11. typedef TIntrusivePtr<TLock> TPtr;
  12. bool IsUnique() const {
  13. return RefCount() == 1;
  14. }
  15. TMutex Mutex_;
  16. };
  17. public:
  18. struct TResourceLock : private TNonCopyable {
  19. TResourceLock(TMultiResourceLock& owner, TLock::TPtr lock, TString resourceId)
  20. : Owner_(owner)
  21. , Lock_(std::move(lock))
  22. , ResourceId_(std::move(resourceId))
  23. {
  24. Y_ENSURE(Lock_);
  25. Lock_->Mutex_.Acquire();
  26. }
  27. TResourceLock(TResourceLock&& other)
  28. : Owner_(other.Owner_)
  29. , Lock_(std::move(other.Lock_))
  30. , ResourceId_(std::move(other.ResourceId_))
  31. {
  32. }
  33. TResourceLock& operator=(TResourceLock&&) = delete;
  34. ~TResourceLock() {
  35. if (!Lock_) {
  36. return;
  37. }
  38. Lock_->Mutex_.Release();
  39. // decrement ref count before TryCleanup
  40. Lock_ = nullptr;
  41. Owner_.TryCleanup(ResourceId_);
  42. }
  43. private:
  44. TMultiResourceLock& Owner_;
  45. TLock::TPtr Lock_;
  46. TString ResourceId_;
  47. };
  48. TResourceLock Acquire(TString resourceId);
  49. template <typename F>
  50. auto RunWithLock(TString resourceId, const F& f) -> decltype(f()) {
  51. auto lock = Acquire(std::move(resourceId));
  52. return f();
  53. }
  54. ~TMultiResourceLock();
  55. private:
  56. TLock::TPtr ProvideResourceLock(const TString& resourceId);
  57. void TryCleanup(const TString& resourceId);
  58. private:
  59. TMutex Guard_;
  60. TMap<TString, TLock::TPtr> Locks_;
  61. };
  62. }