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.

369 lines
12 KiB

7 days ago
5 years ago
5 years ago
5 years ago
7 days ago
9 months ago
9 months ago
5 years ago
5 years ago
5 years ago
4 years ago
4 years ago
7 days ago
7 days ago
7 days ago
5 years ago
5 years ago
7 days ago
9 months ago
4 years ago
3 years ago
4 years ago
7 days ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. package weed_server
  2. import (
  3. "errors"
  4. "fmt"
  5. "strings"
  6. "sync/atomic"
  7. "time"
  8. "github.com/seaweedfs/seaweedfs/weed/stats"
  9. "google.golang.org/protobuf/proto"
  10. "github.com/seaweedfs/seaweedfs/weed/filer"
  11. "github.com/seaweedfs/seaweedfs/weed/glog"
  12. "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
  13. "github.com/seaweedfs/seaweedfs/weed/util"
  14. "github.com/seaweedfs/seaweedfs/weed/util/log_buffer"
  15. )
  16. const (
  17. // MaxUnsyncedEvents send empty notification with timestamp when certain amount of events have been filtered
  18. MaxUnsyncedEvents = 1e3
  19. )
  20. func (fs *FilerServer) SubscribeMetadata(req *filer_pb.SubscribeMetadataRequest, stream filer_pb.SeaweedFiler_SubscribeMetadataServer) error {
  21. ctx := stream.Context()
  22. peerAddress := findClientAddress(ctx, 0)
  23. isReplacing, alreadyKnown, clientName := fs.addClient("", req.ClientName, peerAddress, req.ClientId, req.ClientEpoch)
  24. if isReplacing {
  25. fs.filer.MetaAggregator.ListenersCond.Broadcast() // nudges the subscribers that are waiting
  26. } else if alreadyKnown {
  27. fs.filer.MetaAggregator.ListenersCond.Broadcast() // nudges the subscribers that are waiting
  28. return fmt.Errorf("duplicated subscription detected for client %s id %d", clientName, req.ClientId)
  29. }
  30. defer func() {
  31. glog.V(0).Infof("disconnect %v subscriber %s clientId:%d", clientName, req.PathPrefix, req.ClientId)
  32. fs.deleteClient("", clientName, req.ClientId, req.ClientEpoch)
  33. fs.filer.MetaAggregator.ListenersCond.Broadcast() // nudges the subscribers that are waiting
  34. }()
  35. lastReadTime := log_buffer.NewMessagePosition(req.SinceNs, -2)
  36. glog.V(0).Infof(" %v starts to subscribe %s from %+v", clientName, req.PathPrefix, lastReadTime)
  37. eachEventNotificationFn := fs.eachEventNotificationFn(req, stream, clientName)
  38. eachLogEntryFn := eachLogEntryFn(eachEventNotificationFn)
  39. var processedTsNs int64
  40. var readPersistedLogErr error
  41. var readInMemoryLogErr error
  42. var isDone bool
  43. for {
  44. glog.V(4).Infof("read on disk %v aggregated subscribe %s from %+v", clientName, req.PathPrefix, lastReadTime)
  45. processedTsNs, isDone, readPersistedLogErr = fs.filer.ReadPersistedLogBuffer(lastReadTime, req.UntilNs, eachLogEntryFn)
  46. if readPersistedLogErr != nil {
  47. return fmt.Errorf("reading from persisted logs: %v", readPersistedLogErr)
  48. }
  49. if isDone {
  50. return nil
  51. }
  52. glog.V(4).Infof("processed to %v: %v", clientName, processedTsNs)
  53. if processedTsNs != 0 {
  54. lastReadTime = log_buffer.NewMessagePosition(processedTsNs, -2)
  55. } else {
  56. nextDayTs := util.GetNextDayTsNano(lastReadTime.UnixNano())
  57. position := log_buffer.NewMessagePosition(nextDayTs, -2)
  58. found, err := fs.filer.HasPersistedLogFiles(position)
  59. if err != nil {
  60. return fmt.Errorf("checking persisted log files: %v", err)
  61. }
  62. if found {
  63. lastReadTime = position
  64. }
  65. }
  66. glog.V(4).Infof("read in memory %v aggregated subscribe %s from %+v", clientName, req.PathPrefix, lastReadTime)
  67. lastReadTime, isDone, readInMemoryLogErr = fs.filer.MetaAggregator.MetaLogBuffer.LoopProcessLogData("aggMeta:"+clientName, lastReadTime, req.UntilNs, func() bool {
  68. // Check if the client has disconnected by monitoring the context
  69. select {
  70. case <-ctx.Done():
  71. return false
  72. default:
  73. }
  74. fs.filer.MetaAggregator.ListenersLock.Lock()
  75. fs.filer.MetaAggregator.ListenersCond.Wait()
  76. fs.filer.MetaAggregator.ListenersLock.Unlock()
  77. return fs.hasClient(req.ClientId, req.ClientEpoch)
  78. }, eachLogEntryFn)
  79. if readInMemoryLogErr != nil {
  80. if errors.Is(readInMemoryLogErr, log_buffer.ResumeFromDiskError) {
  81. continue
  82. }
  83. glog.Errorf("processed to %v: %v", lastReadTime, readInMemoryLogErr)
  84. if !errors.Is(readInMemoryLogErr, log_buffer.ResumeError) {
  85. break
  86. }
  87. }
  88. if isDone {
  89. return nil
  90. }
  91. if !fs.hasClient(req.ClientId, req.ClientEpoch) {
  92. glog.V(0).Infof("client %v is closed", clientName)
  93. return nil
  94. }
  95. time.Sleep(1127 * time.Millisecond)
  96. }
  97. return readInMemoryLogErr
  98. }
  99. func (fs *FilerServer) SubscribeLocalMetadata(req *filer_pb.SubscribeMetadataRequest, stream filer_pb.SeaweedFiler_SubscribeLocalMetadataServer) error {
  100. ctx := stream.Context()
  101. peerAddress := findClientAddress(ctx, 0)
  102. // use negative client id to differentiate from addClient()/deleteClient() used in SubscribeMetadata()
  103. req.ClientId = -req.ClientId
  104. isReplacing, alreadyKnown, clientName := fs.addClient("local", req.ClientName, peerAddress, req.ClientId, req.ClientEpoch)
  105. if isReplacing {
  106. fs.listenersCond.Broadcast() // nudges the subscribers that are waiting
  107. } else if alreadyKnown {
  108. return fmt.Errorf("duplicated local subscription detected for client %s clientId:%d", clientName, req.ClientId)
  109. }
  110. defer func() {
  111. glog.V(0).Infof("disconnect %v local subscriber %s clientId:%d", clientName, req.PathPrefix, req.ClientId)
  112. fs.deleteClient("local", clientName, req.ClientId, req.ClientEpoch)
  113. fs.listenersCond.Broadcast() // nudges the subscribers that are waiting
  114. }()
  115. lastReadTime := log_buffer.NewMessagePosition(req.SinceNs, -2)
  116. glog.V(0).Infof(" + %v local subscribe %s from %+v clientId:%d", clientName, req.PathPrefix, lastReadTime, req.ClientId)
  117. eachEventNotificationFn := fs.eachEventNotificationFn(req, stream, clientName)
  118. eachLogEntryFn := eachLogEntryFn(eachEventNotificationFn)
  119. var processedTsNs int64
  120. var readPersistedLogErr error
  121. var readInMemoryLogErr error
  122. var isDone bool
  123. for {
  124. // println("reading from persisted logs ...")
  125. glog.V(0).Infof("read on disk %v local subscribe %s from %+v", clientName, req.PathPrefix, lastReadTime)
  126. processedTsNs, isDone, readPersistedLogErr = fs.filer.ReadPersistedLogBuffer(lastReadTime, req.UntilNs, eachLogEntryFn)
  127. if readPersistedLogErr != nil {
  128. glog.V(0).Infof("read on disk %v local subscribe %s from %+v: %v", clientName, req.PathPrefix, lastReadTime, readPersistedLogErr)
  129. return fmt.Errorf("reading from persisted logs: %v", readPersistedLogErr)
  130. }
  131. if isDone {
  132. return nil
  133. }
  134. if processedTsNs != 0 {
  135. lastReadTime = log_buffer.NewMessagePosition(processedTsNs, -2)
  136. } else {
  137. if readInMemoryLogErr == log_buffer.ResumeFromDiskError {
  138. time.Sleep(1127 * time.Millisecond)
  139. continue
  140. }
  141. }
  142. glog.V(0).Infof("read in memory %v local subscribe %s from %+v", clientName, req.PathPrefix, lastReadTime)
  143. lastReadTime, isDone, readInMemoryLogErr = fs.filer.LocalMetaLogBuffer.LoopProcessLogData("localMeta:"+clientName, lastReadTime, req.UntilNs, func() bool {
  144. // Check if the client has disconnected by monitoring the context
  145. select {
  146. case <-ctx.Done():
  147. return false
  148. default:
  149. }
  150. fs.listenersLock.Lock()
  151. atomic.AddInt64(&fs.listenersWaits, 1)
  152. fs.listenersCond.Wait()
  153. atomic.AddInt64(&fs.listenersWaits, -1)
  154. fs.listenersLock.Unlock()
  155. if !fs.hasClient(req.ClientId, req.ClientEpoch) {
  156. return false
  157. }
  158. return true
  159. }, eachLogEntryFn)
  160. if readInMemoryLogErr != nil {
  161. if readInMemoryLogErr == log_buffer.ResumeFromDiskError {
  162. continue
  163. }
  164. glog.Errorf("processed to %v: %v", lastReadTime, readInMemoryLogErr)
  165. if readInMemoryLogErr != log_buffer.ResumeError {
  166. break
  167. }
  168. }
  169. if isDone {
  170. return nil
  171. }
  172. if !fs.hasClient(req.ClientId, req.ClientEpoch) {
  173. return nil
  174. }
  175. }
  176. return readInMemoryLogErr
  177. }
  178. func eachLogEntryFn(eachEventNotificationFn func(dirPath string, eventNotification *filer_pb.EventNotification, tsNs int64) error) log_buffer.EachLogEntryFuncType {
  179. return func(logEntry *filer_pb.LogEntry) (bool, error) {
  180. event := &filer_pb.SubscribeMetadataResponse{}
  181. if err := proto.Unmarshal(logEntry.Data, event); err != nil {
  182. glog.Errorf("unexpected unmarshal filer_pb.SubscribeMetadataResponse: %v", err)
  183. return false, fmt.Errorf("unexpected unmarshal filer_pb.SubscribeMetadataResponse: %v", err)
  184. }
  185. if err := eachEventNotificationFn(event.Directory, event.EventNotification, event.TsNs); err != nil {
  186. return false, err
  187. }
  188. return false, nil
  189. }
  190. }
  191. func (fs *FilerServer) eachEventNotificationFn(req *filer_pb.SubscribeMetadataRequest, stream filer_pb.SeaweedFiler_SubscribeMetadataServer, clientName string) func(dirPath string, eventNotification *filer_pb.EventNotification, tsNs int64) error {
  192. filtered := 0
  193. return func(dirPath string, eventNotification *filer_pb.EventNotification, tsNs int64) error {
  194. defer func() {
  195. if filtered > MaxUnsyncedEvents {
  196. if err := stream.Send(&filer_pb.SubscribeMetadataResponse{
  197. EventNotification: &filer_pb.EventNotification{},
  198. TsNs: tsNs,
  199. }); err == nil {
  200. filtered = 0
  201. }
  202. }
  203. }()
  204. filtered++
  205. foundSelf := false
  206. for _, sig := range eventNotification.Signatures {
  207. if sig == req.Signature && req.Signature != 0 {
  208. return nil
  209. }
  210. if sig == fs.filer.Signature {
  211. foundSelf = true
  212. }
  213. }
  214. if !foundSelf {
  215. eventNotification.Signatures = append(eventNotification.Signatures, fs.filer.Signature)
  216. }
  217. // get complete path to the file or directory
  218. var entryName string
  219. if eventNotification.OldEntry != nil {
  220. entryName = eventNotification.OldEntry.Name
  221. } else if eventNotification.NewEntry != nil {
  222. entryName = eventNotification.NewEntry.Name
  223. }
  224. fullpath := util.Join(dirPath, entryName)
  225. // skip on filer internal meta logs
  226. if strings.HasPrefix(fullpath, filer.SystemLogDir) {
  227. return nil
  228. }
  229. if hasPrefixIn(fullpath, req.PathPrefixes) {
  230. // good
  231. } else if matchByDirectory(dirPath, req.Directories) {
  232. // good
  233. } else {
  234. if !strings.HasPrefix(fullpath, req.PathPrefix) {
  235. if eventNotification.NewParentPath != "" {
  236. newFullPath := util.Join(eventNotification.NewParentPath, entryName)
  237. if !strings.HasPrefix(newFullPath, req.PathPrefix) {
  238. return nil
  239. }
  240. } else {
  241. return nil
  242. }
  243. }
  244. }
  245. // collect timestamps for path
  246. stats.FilerServerLastSendTsOfSubscribeGauge.WithLabelValues(fs.option.Host.String(), req.ClientName, req.PathPrefix).Set(float64(tsNs))
  247. message := &filer_pb.SubscribeMetadataResponse{
  248. Directory: dirPath,
  249. EventNotification: eventNotification,
  250. TsNs: tsNs,
  251. }
  252. // println("sending", dirPath, entryName)
  253. if err := stream.Send(message); err != nil {
  254. glog.V(0).Infof("=> client %v: %+v", clientName, err)
  255. return err
  256. }
  257. filtered = 0
  258. return nil
  259. }
  260. }
  261. func hasPrefixIn(text string, prefixes []string) bool {
  262. for _, p := range prefixes {
  263. if strings.HasPrefix(text, p) {
  264. return true
  265. }
  266. }
  267. return false
  268. }
  269. func matchByDirectory(dirPath string, directories []string) bool {
  270. for _, dir := range directories {
  271. if dirPath == dir {
  272. return true
  273. }
  274. }
  275. return false
  276. }
  277. func (fs *FilerServer) addClient(prefix string, clientType string, clientAddress string, clientId int32, clientEpoch int32) (isReplacing, alreadyKnown bool, clientName string) {
  278. clientName = clientType + "@" + clientAddress
  279. glog.V(0).Infof("+ %v listener %v clientId %v clientEpoch %v", prefix, clientName, clientId, clientEpoch)
  280. if clientId != 0 {
  281. fs.knownListenersLock.Lock()
  282. defer fs.knownListenersLock.Unlock()
  283. epoch, found := fs.knownListeners[clientId]
  284. if !found || epoch < clientEpoch {
  285. fs.knownListeners[clientId] = clientEpoch
  286. isReplacing = true
  287. } else {
  288. alreadyKnown = true
  289. }
  290. }
  291. return
  292. }
  293. func (fs *FilerServer) deleteClient(prefix string, clientName string, clientId int32, clientEpoch int32) {
  294. glog.V(0).Infof("- %v listener %v clientId %v clientEpoch %v", prefix, clientName, clientId, clientEpoch)
  295. if clientId != 0 {
  296. fs.knownListenersLock.Lock()
  297. defer fs.knownListenersLock.Unlock()
  298. epoch, found := fs.knownListeners[clientId]
  299. if found && epoch <= clientEpoch {
  300. delete(fs.knownListeners, clientId)
  301. }
  302. }
  303. }
  304. func (fs *FilerServer) hasClient(clientId int32, clientEpoch int32) bool {
  305. if clientId != 0 {
  306. fs.knownListenersLock.Lock()
  307. defer fs.knownListenersLock.Unlock()
  308. epoch, found := fs.knownListeners[clientId]
  309. if found && epoch <= clientEpoch {
  310. return true
  311. }
  312. }
  313. return false
  314. }