vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/binlog_watcher.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package tabletserver
    18  
    19  import (
    20  	"sync"
    21  	"time"
    22  
    23  	"context"
    24  
    25  	"vitess.io/vitess/go/vt/log"
    26  	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"
    27  
    28  	binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
    29  )
    30  
    31  // VStreamer defines  the functions of VStreamer
    32  // that the BinlogWatcher needs.
    33  type VStreamer interface {
    34  	Stream(ctx context.Context, startPos string, tablePKs []*binlogdatapb.TableLastPK, filter *binlogdatapb.Filter, send func([]*binlogdatapb.VEvent) error) error
    35  }
    36  
    37  // BinlogWatcher is a tabletserver service that watches the
    38  // replication stream.  It will trigger schema reloads if a DDL
    39  // is encountered.
    40  type BinlogWatcher struct {
    41  	env              tabletenv.Env
    42  	watchReplication bool
    43  	vs               VStreamer
    44  
    45  	cancel context.CancelFunc
    46  	wg     sync.WaitGroup
    47  }
    48  
    49  // NewBinlogWatcher creates a new BinlogWatcher.
    50  func NewBinlogWatcher(env tabletenv.Env, vs VStreamer, config *tabletenv.TabletConfig) *BinlogWatcher {
    51  	return &BinlogWatcher{
    52  		env:              env,
    53  		vs:               vs,
    54  		watchReplication: config.WatchReplication || config.TrackSchemaVersions,
    55  	}
    56  }
    57  
    58  // Open starts the BinlogWatcher service.
    59  func (blw *BinlogWatcher) Open() {
    60  	if blw.cancel != nil || !blw.watchReplication {
    61  		return
    62  	}
    63  	log.Info("Binlog Watcher: opening")
    64  
    65  	ctx, cancel := context.WithCancel(tabletenv.LocalContext())
    66  	blw.cancel = cancel
    67  	blw.wg.Add(1)
    68  	go blw.process(ctx)
    69  }
    70  
    71  // Close stops the BinlogWatcher service.
    72  func (blw *BinlogWatcher) Close() {
    73  	if blw.cancel == nil {
    74  		return
    75  	}
    76  	blw.cancel()
    77  	blw.cancel = nil
    78  	blw.wg.Wait()
    79  	log.Info("Binlog Watcher: closed")
    80  }
    81  
    82  func (blw *BinlogWatcher) process(ctx context.Context) {
    83  	defer blw.env.LogError()
    84  	defer blw.wg.Done()
    85  
    86  	filter := &binlogdatapb.Filter{
    87  		Rules: []*binlogdatapb.Rule{{
    88  			Match: "/.*",
    89  		}},
    90  	}
    91  
    92  	for {
    93  		// VStreamer will reload the schema when it encounters a DDL.
    94  		err := blw.vs.Stream(ctx, "current", nil, filter, func(events []*binlogdatapb.VEvent) error {
    95  			return nil
    96  		})
    97  		log.Infof("ReplicationWatcher VStream ended: %v, retrying in 5 seconds", err)
    98  		select {
    99  		case <-ctx.Done():
   100  			return
   101  		case <-time.After(5 * time.Second):
   102  		}
   103  	}
   104  }