// Starts a changeListener on a given Bucket. func (listener *changeListener) Start(bucket base.Bucket) error { listener.bucket = bucket tapFeed, err := bucket.StartTapFeed(walrus.TapArguments{Backfill: walrus.TapNoBackfill}) if err != nil { return err } listener.tapFeed = tapFeed listener.counter = 1 listener.tapNotifier = sync.NewCond(&sync.Mutex{}) // Start a goroutine to broadcast to the tapNotifier whenever a channel or user/role changes: go func() { defer listener.notify("") for event := range tapFeed.Events() { if event.Opcode == walrus.TapMutation || event.Opcode == walrus.TapDeletion { key := string(event.Key) if strings.HasPrefix(key, kChannelLogKeyPrefix) || strings.HasPrefix(key, auth.UserKeyPrefix) || strings.HasPrefix(key, auth.RoleKeyPrefix) { listener.notify(key) } } } }() return nil }
func NewDatabaseContext(dbName string, bucket base.Bucket) (*DatabaseContext, error) { context := &DatabaseContext{ Name: dbName, Bucket: bucket, tapNotifier: sync.NewCond(&sync.Mutex{}), } var err error context.sequences, err = newSequenceAllocator(bucket) if err != nil { return nil, err } tapFeed, err := bucket.StartTapFeed(walrus.TapArguments{Backfill: walrus.TapNoBackfill}) if err != nil { return nil, err } // Start a goroutine to broadcast to the tapNotifier whenever a document changes: go func() { for event := range tapFeed.Events() { if event.Opcode == walrus.TapMutation || event.Opcode == walrus.TapDeletion { key := string(event.Key) if strings.HasPrefix(key, "_sync:") && !strings.HasPrefix(key, "_sync:user") && !strings.HasPrefix(key, "_sync:role") { continue // ignore metadata docs (sequence counter, attachments, local docs...) } base.LogTo("Changes", "Notifying that %q changed (key=%q)", dbName, event.Key) context.tapNotifier.Broadcast() } } }() return context, nil }
// Creates a new Shadower. func NewShadower(context *DatabaseContext, bucket base.Bucket, docIDPattern *regexp.Regexp) (*Shadower, error) { tapFeed, err := bucket.StartTapFeed(walrus.TapArguments{Backfill: 0}) if err != nil { return nil, err } s := &Shadower{context: context, bucket: bucket, tapFeed: tapFeed, docIDPattern: docIDPattern} go s.readTapFeed() return s, nil }
// Starts a changeListener on a given Bucket. func (listener *changeListener) Start(bucket base.Bucket, trackDocs bool) error { listener.bucket = bucket tapFeed, err := bucket.StartTapFeed(walrus.TapArguments{Backfill: walrus.TapNoBackfill}) if err != nil { return err } listener.tapFeed = tapFeed listener.counter = 1 listener.keyCounts = map[string]uint64{} listener.tapNotifier = sync.NewCond(&sync.Mutex{}) if trackDocs { listener.DocChannel = make(chan walrus.TapEvent, 100) } // Start a goroutine to broadcast to the tapNotifier whenever a channel or user/role changes: go func() { defer func() { listener.notify("") if listener.DocChannel != nil { close(listener.DocChannel) } }() for event := range tapFeed.Events() { if event.Opcode == walrus.TapMutation || event.Opcode == walrus.TapDeletion { key := string(event.Key) if strings.HasPrefix(key, kChannelLogKeyPrefix) { if listener.OnChannelChanged != nil { channelName := string(event.Key)[len(kChannelLogKeyPrefix):] // Notify the client synchronously via a fn call, instead of by writing // to a channel, to ensure that the client can cache the updated channel // log before any subsequent document change is processed. listener.OnChannelChanged(channelName, event.Value) } listener.notify(key) } else if strings.HasPrefix(key, auth.UserKeyPrefix) || strings.HasPrefix(key, auth.RoleKeyPrefix) { listener.notify(key) } else if trackDocs && !strings.HasPrefix(key, kSyncKeyPrefix) { listener.DocChannel <- event } } } }() return nil }
// Starts a changeListener on a given Bucket. func (listener *changeListener) Start(bucket base.Bucket, trackDocs bool) error { listener.bucket = bucket tapFeed, err := bucket.StartTapFeed(walrus.TapArguments{Backfill: walrus.TapNoBackfill}) if err != nil { return err } listener.tapFeed = tapFeed listener.counter = 1 listener.keyCounts = map[string]uint64{} listener.tapNotifier = sync.NewCond(&sync.Mutex{}) if trackDocs { listener.DocChannel = make(chan walrus.TapEvent, 100) } // Start a goroutine to broadcast to the tapNotifier whenever a channel or user/role changes: go func() { defer func() { listener.notifyStopping() if listener.DocChannel != nil { close(listener.DocChannel) } }() for event := range tapFeed.Events() { if event.Opcode == walrus.TapMutation || event.Opcode == walrus.TapDeletion { key := string(event.Key) if strings.HasPrefix(key, auth.UserKeyPrefix) || strings.HasPrefix(key, auth.RoleKeyPrefix) { if listener.OnDocChanged != nil { listener.OnDocChanged(key, event.Value) } listener.Notify(base.SetOf(key)) } else if trackDocs && !strings.HasPrefix(key, kSyncKeyPrefix) { if listener.OnDocChanged != nil { listener.OnDocChanged(key, event.Value) } listener.DocChannel <- event } } } }() return nil }