vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/messager/engine.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 messager
    18  
    19  import (
    20  	"context"
    21  	"sync"
    22  
    23  	"vitess.io/vitess/go/sqltypes"
    24  	"vitess.io/vitess/go/sync2"
    25  	"vitess.io/vitess/go/vt/log"
    26  	"vitess.io/vitess/go/vt/vterrors"
    27  	"vitess.io/vitess/go/vt/vttablet/tabletserver/schema"
    28  	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"
    29  
    30  	binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
    31  	querypb "vitess.io/vitess/go/vt/proto/query"
    32  	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
    33  )
    34  
    35  // TabletService defines the functions of TabletServer
    36  // that the messager needs for callback.
    37  type TabletService interface {
    38  	tabletenv.Env
    39  	PostponeMessages(ctx context.Context, target *querypb.Target, querygen QueryGenerator, ids []string) (count int64, err error)
    40  	PurgeMessages(ctx context.Context, target *querypb.Target, querygen QueryGenerator, timeCutoff int64) (count int64, err error)
    41  }
    42  
    43  // VStreamer defines  the functions of VStreamer
    44  // that the messager needs.
    45  type VStreamer interface {
    46  	Stream(ctx context.Context, startPos string, tablePKs []*binlogdatapb.TableLastPK, filter *binlogdatapb.Filter, send func([]*binlogdatapb.VEvent) error) error
    47  	StreamResults(ctx context.Context, query string, send func(*binlogdatapb.VStreamResultsResponse) error) error
    48  }
    49  
    50  // Engine is the engine for handling messages.
    51  type Engine struct {
    52  	mu       sync.Mutex
    53  	isOpen   bool
    54  	managers map[string]*messageManager
    55  
    56  	tsv          TabletService
    57  	se           *schema.Engine
    58  	vs           VStreamer
    59  	postponeSema *sync2.Semaphore
    60  }
    61  
    62  // NewEngine creates a new Engine.
    63  func NewEngine(tsv TabletService, se *schema.Engine, vs VStreamer) *Engine {
    64  	return &Engine{
    65  		tsv:          tsv,
    66  		se:           se,
    67  		vs:           vs,
    68  		postponeSema: sync2.NewSemaphore(tsv.Config().MessagePostponeParallelism, 0),
    69  		managers:     make(map[string]*messageManager),
    70  	}
    71  }
    72  
    73  // Open starts the Engine service.
    74  func (me *Engine) Open() {
    75  	me.mu.Lock()
    76  	if me.isOpen {
    77  		me.mu.Unlock()
    78  		return
    79  	}
    80  	me.isOpen = true
    81  	me.mu.Unlock()
    82  	log.Info("Messager: opening")
    83  	// Unlock before invoking RegisterNotifier because it
    84  	// obtains the same lock.
    85  	me.se.RegisterNotifier("messages", me.schemaChanged)
    86  }
    87  
    88  // Close closes the Engine service.
    89  func (me *Engine) Close() {
    90  	log.Infof("messager Engine - started execution of Close. Acquiring mu lock")
    91  	me.mu.Lock()
    92  	log.Infof("messager Engine - acquired mu lock")
    93  	defer me.mu.Unlock()
    94  	if !me.isOpen {
    95  		log.Infof("messager Engine is not open")
    96  		return
    97  	}
    98  	me.isOpen = false
    99  	log.Infof("messager Engine - unregistering notifiers")
   100  	me.se.UnregisterNotifier("messages")
   101  	log.Infof("messager Engine - closing all managers")
   102  	for _, mm := range me.managers {
   103  		mm.Close()
   104  	}
   105  	me.managers = make(map[string]*messageManager)
   106  	log.Info("Messager: closed")
   107  }
   108  
   109  func (me *Engine) GetGenerator(name string) (QueryGenerator, error) {
   110  	me.mu.Lock()
   111  	defer me.mu.Unlock()
   112  	mm := me.managers[name]
   113  	if mm == nil {
   114  		return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "message table %s not found in schema", name)
   115  	}
   116  	return mm, nil
   117  }
   118  
   119  // Subscribe subscribes to messages from the requested table.
   120  // The function returns a done channel that will be closed when
   121  // the subscription ends, which can be initiated by the send function
   122  // returning io.EOF. The engine can also end a subscription which is
   123  // usually triggered by Close. It's the responsibility of the send
   124  // function to promptly return if the done channel is closed. Otherwise,
   125  // the engine's Close function will hang indefinitely.
   126  func (me *Engine) Subscribe(ctx context.Context, name string, send func(*sqltypes.Result) error) (done <-chan struct{}, err error) {
   127  	me.mu.Lock()
   128  	defer me.mu.Unlock()
   129  	if !me.isOpen {
   130  		return nil, vterrors.Errorf(vtrpcpb.Code_UNAVAILABLE, "messager engine is closed, probably because this is not a primary any more")
   131  	}
   132  	mm := me.managers[name]
   133  	if mm == nil {
   134  		return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "message table %s not found", name)
   135  	}
   136  	return mm.Subscribe(ctx, send), nil
   137  }
   138  
   139  func (me *Engine) schemaChanged(tables map[string]*schema.Table, created, altered, dropped []string) {
   140  	me.mu.Lock()
   141  	defer me.mu.Unlock()
   142  	for _, name := range append(dropped, altered...) {
   143  		mm := me.managers[name]
   144  		if mm == nil {
   145  			continue
   146  		}
   147  		log.Infof("Stopping messager for dropped/updated table: %v", name)
   148  		mm.Close()
   149  		delete(me.managers, name)
   150  	}
   151  
   152  	for _, name := range append(created, altered...) {
   153  		t := tables[name]
   154  		if t.Type != schema.Message {
   155  			continue
   156  		}
   157  		if me.managers[name] != nil {
   158  			me.tsv.Stats().InternalErrors.Add("Messages", 1)
   159  			log.Errorf("Newly created table already exists in messages: %s", name)
   160  			continue
   161  		}
   162  		mm := newMessageManager(me.tsv, me.vs, t, me.postponeSema)
   163  		me.managers[name] = mm
   164  		log.Infof("Starting messager for table: %v", name)
   165  		mm.Open()
   166  	}
   167  }