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.

101 lines
2.3 KiB

  1. package broker
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. "github.com/chrislusf/seaweedfs/weed/filer2"
  7. "github.com/chrislusf/seaweedfs/weed/glog"
  8. "github.com/chrislusf/seaweedfs/weed/pb/messaging_pb"
  9. "github.com/chrislusf/seaweedfs/weed/util/log_buffer"
  10. )
  11. type TopicPartition struct {
  12. Namespace string
  13. Topic string
  14. Partition int32
  15. }
  16. type TopicLock struct {
  17. sync.Mutex
  18. cond *sync.Cond
  19. subscriberCount int
  20. publisherCount int
  21. logBuffer *log_buffer.LogBuffer
  22. }
  23. type TopicLocks struct {
  24. sync.Mutex
  25. locks map[TopicPartition]*TopicLock
  26. broker *MessageBroker
  27. }
  28. func NewTopicLocks(messageBroker *MessageBroker) *TopicLocks {
  29. return &TopicLocks{
  30. locks: make(map[TopicPartition]*TopicLock),
  31. broker: messageBroker,
  32. }
  33. }
  34. func (locks *TopicLocks) buildLogBuffer(tl *TopicLock, tp TopicPartition, topicConfig *messaging_pb.TopicConfiguration) *log_buffer.LogBuffer {
  35. flushFn := func(startTime, stopTime time.Time, buf []byte) {
  36. if topicConfig.IsTransient {
  37. return
  38. }
  39. targetFile := fmt.Sprintf(
  40. "%s/%s/%s/%04d-%02d-%02d/%02d-%02d.part%02d",
  41. filer2.TopicsDir, tp.Namespace, tp.Topic,
  42. startTime.Year(), startTime.Month(), startTime.Day(), startTime.Hour(), startTime.Minute(),
  43. tp.Partition,
  44. )
  45. if err := locks.broker.appendToFile(targetFile, topicConfig, buf); err != nil {
  46. glog.V(0).Infof("log write failed %s: %v", targetFile, err)
  47. }
  48. }
  49. logBuffer := log_buffer.NewLogBuffer(time.Minute, flushFn, func() {
  50. tl.cond.Broadcast()
  51. })
  52. return logBuffer
  53. }
  54. func (tl *TopicLocks) RequestLock(partition TopicPartition, topicConfig *messaging_pb.TopicConfiguration, isPublisher bool) *TopicLock {
  55. tl.Lock()
  56. defer tl.Unlock()
  57. lock, found := tl.locks[partition]
  58. if !found {
  59. lock = &TopicLock{}
  60. lock.cond = sync.NewCond(&lock.Mutex)
  61. tl.locks[partition] = lock
  62. lock.logBuffer = tl.buildLogBuffer(lock, partition, topicConfig)
  63. }
  64. if isPublisher {
  65. lock.publisherCount++
  66. } else {
  67. lock.subscriberCount++
  68. }
  69. return lock
  70. }
  71. func (tl *TopicLocks) ReleaseLock(partition TopicPartition, isPublisher bool) {
  72. tl.Lock()
  73. defer tl.Unlock()
  74. lock, found := tl.locks[partition]
  75. if !found {
  76. return
  77. }
  78. if isPublisher {
  79. lock.publisherCount--
  80. } else {
  81. lock.subscriberCount--
  82. }
  83. if lock.subscriberCount <= 0 && lock.publisherCount <= 0 {
  84. delete(tl.locks, partition)
  85. }
  86. }