You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

107 lines
2.9 KiB

  1. // Copyright 2017 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package pubsub
  15. import (
  16. "golang.org/x/net/context"
  17. "golang.org/x/sync/semaphore"
  18. )
  19. // flowController implements flow control for Subscription.Receive.
  20. type flowController struct {
  21. maxSize int // max total size of messages
  22. semCount, semSize *semaphore.Weighted // enforces max number and size of messages
  23. }
  24. // newFlowController creates a new flowController that ensures no more than
  25. // maxCount messages or maxSize bytes are outstanding at once. If maxCount or
  26. // maxSize is < 1, then an unlimited number of messages or bytes is permitted,
  27. // respectively.
  28. func newFlowController(maxCount, maxSize int) *flowController {
  29. fc := &flowController{
  30. maxSize: maxSize,
  31. semCount: nil,
  32. semSize: nil,
  33. }
  34. if maxCount > 0 {
  35. fc.semCount = semaphore.NewWeighted(int64(maxCount))
  36. }
  37. if maxSize > 0 {
  38. fc.semSize = semaphore.NewWeighted(int64(maxSize))
  39. }
  40. return fc
  41. }
  42. // acquire blocks until one message of size bytes can proceed or ctx is done.
  43. // It returns nil in the first case, or ctx.Err() in the second.
  44. //
  45. // acquire allows large messages to proceed by treating a size greater than maxSize
  46. // as if it were equal to maxSize.
  47. func (f *flowController) acquire(ctx context.Context, size int) error {
  48. if f.semCount != nil {
  49. if err := f.semCount.Acquire(ctx, 1); err != nil {
  50. return err
  51. }
  52. }
  53. if f.semSize != nil {
  54. if err := f.semSize.Acquire(ctx, f.bound(size)); err != nil {
  55. if f.semCount != nil {
  56. f.semCount.Release(1)
  57. }
  58. return err
  59. }
  60. }
  61. return nil
  62. }
  63. // tryAcquire returns false if acquire would block. Otherwise, it behaves like
  64. // acquire and returns true.
  65. //
  66. // tryAcquire allows large messages to proceed by treating a size greater than
  67. // maxSize as if it were equal to maxSize.
  68. func (f *flowController) tryAcquire(size int) bool {
  69. if f.semCount != nil {
  70. if !f.semCount.TryAcquire(1) {
  71. return false
  72. }
  73. }
  74. if f.semSize != nil {
  75. if !f.semSize.TryAcquire(f.bound(size)) {
  76. if f.semCount != nil {
  77. f.semCount.Release(1)
  78. }
  79. return false
  80. }
  81. }
  82. return true
  83. }
  84. // release notes that one message of size bytes is no longer outstanding.
  85. func (f *flowController) release(size int) {
  86. if f.semCount != nil {
  87. f.semCount.Release(1)
  88. }
  89. if f.semSize != nil {
  90. f.semSize.Release(f.bound(size))
  91. }
  92. }
  93. func (f *flowController) bound(size int) int64 {
  94. if size > f.maxSize {
  95. return int64(f.maxSize)
  96. }
  97. return int64(size)
  98. }