github.com/go-graphite/carbonapi@v0.17.0/zipper/types/response.go (about)

     1  package types
     2  
     3  import (
     4  	"context"
     5  	"math"
     6  
     7  	"github.com/ansel1/merry"
     8  
     9  	protov3 "github.com/go-graphite/protocol/carbonapi_v3_pb"
    10  	"github.com/lomik/zapwriter"
    11  	"go.uber.org/zap"
    12  )
    13  
    14  // type Fetcher func(ctx context.Context, logger *zap.Logger, client types.BackendServer, reqs interface{}, resCh chan<- types.ServerFetchResponse) {
    15  // type Fetcher func(ctx context.Context, logger *zap.Logger, client BackendServer, reqs interface{}, resCh chan ServerFetchResponse) {
    16  type Fetcher func(ctx context.Context, logger *zap.Logger, client BackendServer, reqs interface{}, resCh chan ServerFetcherResponse)
    17  
    18  type ServerFetcherResponse interface {
    19  	Self() interface{}
    20  	MergeI(second ServerFetcherResponse) merry.Error
    21  	AddError(err merry.Error)
    22  	Errors() []merry.Error
    23  	GetServer() string
    24  }
    25  
    26  func NoAnswerBackends(backends []BackendServer, answered map[string]struct{}) []string {
    27  	noAnswer := make([]string, 0)
    28  	for _, s := range backends {
    29  		if _, ok := answered[s.Name()]; !ok {
    30  			noAnswer = append(noAnswer, s.Name())
    31  		}
    32  	}
    33  
    34  	return noAnswer
    35  }
    36  
    37  // Helper function
    38  func DoRequest(ctx context.Context, logger *zap.Logger, clients []BackendServer, result ServerFetcherResponse, request interface{}, fetcher Fetcher) (ServerFetcherResponse, int) {
    39  	resCh := make(chan ServerFetcherResponse, len(clients))
    40  
    41  	for _, client := range clients {
    42  		logger.Debug("single fetch",
    43  			zap.Any("client", client),
    44  		)
    45  		go fetcher(ctx, logger, client, request, resCh)
    46  	}
    47  
    48  	answeredServers := make(map[string]struct{})
    49  	responseCount := 0
    50  GATHER:
    51  	for responseCount < len(clients) {
    52  		select {
    53  		case res := <-resCh:
    54  			answeredServers[res.GetServer()] = struct{}{}
    55  			if err := result.MergeI(res); err == nil {
    56  				responseCount++
    57  			} else {
    58  				result.AddError(err)
    59  			}
    60  		case <-ctx.Done():
    61  			err := ErrTimeoutExceeded.WithValue("timedout_backends", NoAnswerBackends(clients, answeredServers))
    62  			result.AddError(err)
    63  
    64  			break GATHER
    65  		}
    66  	}
    67  	return result, responseCount
    68  }
    69  
    70  type ServerTagResponse struct {
    71  	Server   string
    72  	Response []string
    73  	Err      []merry.Error
    74  }
    75  
    76  func NewServerTagResponse() *ServerTagResponse {
    77  	return &ServerTagResponse{
    78  		Response: []string{},
    79  	}
    80  }
    81  
    82  func (s *ServerTagResponse) Self() interface{} {
    83  	return s
    84  }
    85  
    86  func (s ServerTagResponse) GetServer() string {
    87  	return s.Server
    88  }
    89  
    90  func (first *ServerTagResponse) MergeI(second ServerFetcherResponse) merry.Error {
    91  	secondSelf := second.Self()
    92  	s, ok := secondSelf.(*ServerTagResponse)
    93  	if !ok {
    94  		return ErrResponseTypeMismatch.Here().WithMessagef("got '%T', expected '%T'", secondSelf, first)
    95  	}
    96  	return first.Merge(s)
    97  }
    98  
    99  func (s *ServerTagResponse) AddError(err merry.Error) {
   100  	if err == nil {
   101  		return
   102  	}
   103  	if s.Err == nil {
   104  		s.Err = []merry.Error{err}
   105  	} else {
   106  		s.Err = append(s.Err, err)
   107  	}
   108  }
   109  
   110  func (first *ServerTagResponse) Errors() []merry.Error {
   111  	return first.Err
   112  }
   113  
   114  func (first *ServerTagResponse) Merge(second *ServerTagResponse) merry.Error {
   115  	if first.Err == nil {
   116  		if second.Err != nil {
   117  			first.Err = second.Err
   118  		}
   119  	} else {
   120  		if second.Err != nil {
   121  			first.Err = append(first.Err, second.Err...)
   122  		}
   123  	}
   124  
   125  	if second.Response == nil {
   126  		return nil
   127  	}
   128  
   129  	// We cannot assume in general that results are sorted
   130  	firstMap := make(map[string]struct{}, len(first.Response))
   131  	for _, v := range first.Response {
   132  		firstMap[v] = struct{}{}
   133  	}
   134  
   135  	for _, v := range second.Response {
   136  		if _, ok := firstMap[v]; !ok {
   137  			first.Response = append(first.Response, v)
   138  		}
   139  	}
   140  
   141  	return nil
   142  }
   143  
   144  type ServerInfoResponse struct {
   145  	Server   string
   146  	Response *protov3.ZipperInfoResponse
   147  	Stats    *Stats
   148  	Err      []merry.Error
   149  }
   150  
   151  func NewServerInfoResponse() *ServerInfoResponse {
   152  	return &ServerInfoResponse{
   153  		Response: &protov3.ZipperInfoResponse{Info: make(map[string]protov3.MultiMetricsInfoResponse)},
   154  		Stats:    new(Stats),
   155  	}
   156  }
   157  
   158  func (s *ServerInfoResponse) Self() interface{} {
   159  	return s
   160  }
   161  
   162  func (s ServerInfoResponse) GetServer() string {
   163  	return s.Server
   164  }
   165  
   166  func (first *ServerInfoResponse) MergeI(second ServerFetcherResponse) merry.Error {
   167  	secondSelf := second.Self()
   168  	s, ok := secondSelf.(*ServerInfoResponse)
   169  	if !ok {
   170  		return ErrResponseTypeMismatch.Here().WithMessagef("got '%T', expected '%T'", secondSelf, first)
   171  	}
   172  	return first.Merge(s)
   173  }
   174  
   175  func (s *ServerInfoResponse) AddError(err merry.Error) {
   176  	if err == nil {
   177  		return
   178  	}
   179  	if s.Err == nil {
   180  		s.Err = []merry.Error{err}
   181  	} else {
   182  		s.Err = append(s.Err, err)
   183  	}
   184  }
   185  
   186  func (first *ServerInfoResponse) Errors() []merry.Error {
   187  	return first.Err
   188  }
   189  
   190  func (first *ServerInfoResponse) Merge(second *ServerInfoResponse) merry.Error {
   191  	if second.Stats != nil {
   192  		first.Stats.Merge(second.Stats)
   193  	}
   194  
   195  	if first.Err == nil {
   196  		if second.Err != nil {
   197  			first.Err = second.Err
   198  		}
   199  	} else {
   200  		if second.Err != nil {
   201  			first.Err = append(first.Err, second.Err...)
   202  		}
   203  	}
   204  
   205  	if second.Response == nil {
   206  		return nil
   207  	}
   208  
   209  	for k, v := range second.Response.Info {
   210  		first.Response.Info[k] = v
   211  	}
   212  
   213  	return nil
   214  }
   215  
   216  type ServerFindResponse struct {
   217  	Server   string
   218  	Response *protov3.MultiGlobResponse
   219  	Stats    *Stats
   220  	Err      []merry.Error
   221  }
   222  
   223  func NewServerFindResponse() *ServerFindResponse {
   224  	return &ServerFindResponse{
   225  		Response: new(protov3.MultiGlobResponse),
   226  		Stats:    new(Stats),
   227  	}
   228  }
   229  
   230  func (s *ServerFindResponse) Self() interface{} {
   231  	return s
   232  }
   233  
   234  func (s ServerFindResponse) GetServer() string {
   235  	return s.Server
   236  }
   237  
   238  func (first *ServerFindResponse) MergeI(second ServerFetcherResponse) merry.Error {
   239  	secondSelf := second.Self()
   240  	s, ok := secondSelf.(*ServerFindResponse)
   241  	if !ok {
   242  		return ErrResponseTypeMismatch.Here().WithMessagef("got '%T', expected '%T'", secondSelf, first)
   243  	}
   244  	return first.Merge(s)
   245  }
   246  
   247  func (s *ServerFindResponse) AddError(err merry.Error) {
   248  	if err == nil {
   249  		return
   250  	}
   251  	if s.Err == nil {
   252  		s.Err = []merry.Error{err}
   253  	} else {
   254  		s.Err = append(s.Err, err)
   255  	}
   256  }
   257  
   258  func (first *ServerFindResponse) Errors() []merry.Error {
   259  	return first.Err
   260  }
   261  
   262  func (first *ServerFindResponse) Merge(second *ServerFindResponse) merry.Error {
   263  	if second.Stats != nil {
   264  		first.Stats.Merge(second.Stats)
   265  	}
   266  
   267  	if first.Err == nil {
   268  		if second.Err != nil {
   269  			first.Err = second.Err
   270  		}
   271  	} else {
   272  		if second.Err != nil {
   273  			first.Err = append(first.Err, second.Err...)
   274  		}
   275  	}
   276  
   277  	if second.Response == nil {
   278  		return nil
   279  	}
   280  
   281  	var ok bool
   282  	seenMetrics := make(map[string]int)
   283  	seenMatches := make(map[string]map[bool]struct{})
   284  	for i, m := range first.Response.Metrics {
   285  		seenMetrics[m.Name] = i
   286  		for _, mm := range m.Matches {
   287  			lkey := m.Name + "." + mm.Path
   288  			if _, ok = seenMatches[lkey]; !ok {
   289  				seenMatches[lkey] = map[bool]struct{}{}
   290  			}
   291  
   292  			seenMatches[lkey][mm.IsLeaf] = struct{}{}
   293  		}
   294  	}
   295  
   296  	var i int
   297  	for _, m := range second.Response.Metrics {
   298  		if i, ok = seenMetrics[m.Name]; !ok {
   299  			first.Response.Metrics = append(first.Response.Metrics, m)
   300  			continue
   301  		}
   302  
   303  		for _, mm := range m.Matches {
   304  			key := first.Response.Metrics[i].Name + "." + mm.Path
   305  			lisLeaf := seenMatches[key]
   306  			if lisLeaf == nil {
   307  				lisLeaf = map[bool]struct{}{}
   308  				seenMatches[key] = lisLeaf
   309  			}
   310  
   311  			if _, ok = lisLeaf[mm.IsLeaf]; !ok {
   312  				lisLeaf[mm.IsLeaf] = struct{}{}
   313  				first.Response.Metrics[i].Matches = append(first.Response.Metrics[i].Matches, mm)
   314  			}
   315  		}
   316  	}
   317  
   318  	return nil
   319  }
   320  
   321  type ServerFetchResponse struct {
   322  	Server   string
   323  	Response *protov3.MultiFetchResponse
   324  	Stats    *Stats
   325  	Err      []merry.Error
   326  }
   327  
   328  func NewServerFetchResponse() *ServerFetchResponse {
   329  	return &ServerFetchResponse{
   330  		Response: new(protov3.MultiFetchResponse),
   331  		Stats:    new(Stats),
   332  	}
   333  }
   334  
   335  func (s *ServerFetchResponse) Self() interface{} {
   336  	return s
   337  }
   338  
   339  func (s ServerFetchResponse) GetServer() string {
   340  	return s.Server
   341  }
   342  
   343  func (first *ServerFetchResponse) Merge(second *ServerFetchResponse) merry.Error {
   344  	if second.Stats != nil {
   345  		first.Stats.Merge(second.Stats)
   346  	}
   347  
   348  	if first.Err == nil {
   349  		if second.Err != nil {
   350  			first.Err = second.Err
   351  		}
   352  	} else {
   353  		if second.Err != nil {
   354  			first.Err = append(first.Err, second.Err...)
   355  		}
   356  	}
   357  
   358  	if second.Response == nil {
   359  		return nil
   360  	}
   361  
   362  	metrics := make(map[fetchResponseCoordinates]int)
   363  	for i := range first.Response.Metrics {
   364  		metrics[coordinates(&first.Response.Metrics[i])] = i
   365  	}
   366  
   367  	for i := range second.Response.Metrics {
   368  		if j, ok := metrics[coordinates(&second.Response.Metrics[i])]; ok {
   369  			err := MergeFetchResponses(&first.Response.Metrics[j], &second.Response.Metrics[i])
   370  			if err != nil {
   371  				// TODO: Normal merry.Error handling
   372  				continue
   373  			}
   374  		} else {
   375  			first.Response.Metrics = append(first.Response.Metrics, second.Response.Metrics[i])
   376  		}
   377  	}
   378  	return nil
   379  }
   380  
   381  func (first *ServerFetchResponse) MergeI(second ServerFetcherResponse) merry.Error {
   382  	secondSelf := second.Self()
   383  	s, ok := secondSelf.(*ServerFetchResponse)
   384  	if !ok {
   385  		return ErrResponseTypeMismatch.Here().WithMessagef("got '%T', expected '%T'", secondSelf, first)
   386  	}
   387  	return first.Merge(s)
   388  }
   389  
   390  func (s *ServerFetchResponse) AddError(err merry.Error) {
   391  	if err == nil {
   392  		return
   393  	}
   394  	if s.Err == nil {
   395  		s.Err = []merry.Error{err}
   396  	} else {
   397  		s.Err = append(s.Err, err)
   398  	}
   399  }
   400  
   401  func (first *ServerFetchResponse) Errors() []merry.Error {
   402  	return first.Err
   403  }
   404  
   405  func (s *ServerFetchResponse) NonFatalError(err merry.Error) *ServerFetchResponse {
   406  	s.AddError(err)
   407  	return s
   408  }
   409  
   410  func swapFetchResponses(m1, m2 *protov3.FetchResponse) {
   411  	m1.Name, m2.Name = m2.Name, m1.Name
   412  	m1.StartTime, m2.StartTime = m2.StartTime, m1.StartTime
   413  	m1.StepTime, m2.StepTime = m2.StepTime, m1.StepTime
   414  	m1.ConsolidationFunc, m2.ConsolidationFunc = m2.ConsolidationFunc, m1.ConsolidationFunc
   415  	m1.XFilesFactor, m2.XFilesFactor = m2.XFilesFactor, m1.XFilesFactor
   416  	m1.Values, m2.Values = m2.Values, m1.Values
   417  	m1.AppliedFunctions, m2.AppliedFunctions = m2.AppliedFunctions, m1.AppliedFunctions
   418  	m1.StopTime, m2.StopTime = m2.StopTime, m1.StopTime
   419  }
   420  
   421  func mergeFetchResponsesWithEqualStepTimes(m1, m2 *protov3.FetchResponse) merry.Error {
   422  	if m1.StartTime != m2.StartTime {
   423  		return ErrResponseStartTimeMismatch
   424  	}
   425  
   426  	if len(m1.Values) < len(m2.Values) {
   427  		swapFetchResponses(m1, m2)
   428  	}
   429  
   430  	for i := 0; i < len(m2.Values); i++ {
   431  		if math.IsNaN(m1.Values[i]) {
   432  			m1.Values[i] = m2.Values[i]
   433  		}
   434  	}
   435  
   436  	return nil
   437  }
   438  
   439  func mergeFetchResponsesWithUnequalStepTimes(m1, m2 *protov3.FetchResponse) merry.Error {
   440  	if m1.StepTime > m2.StepTime {
   441  		swapFetchResponses(m1, m2)
   442  	}
   443  
   444  	zapwriter.Logger("zipper").Warn("Fetch responses had different step times",
   445  		zap.Int64("m1_request_start_time", m1.RequestStartTime),
   446  		zap.Int64("m1_start_time", m1.StartTime),
   447  		zap.Int64("m1_stop_time", m1.StopTime),
   448  		zap.Int64("m1_step_time", m1.StepTime),
   449  		zap.Int64("m2_request_start_time", m2.RequestStartTime),
   450  		zap.Int64("m2_start_time", m2.StartTime),
   451  		zap.Int64("m2_stop_time", m2.StopTime),
   452  		zap.Int64("m2_step_time", m2.StepTime),
   453  	)
   454  
   455  	return nil
   456  }
   457  
   458  func MergeFetchResponses(m1, m2 *protov3.FetchResponse) merry.Error {
   459  	var err merry.Error
   460  	if m1.RequestStartTime != m2.RequestStartTime {
   461  		err = ErrResponseStartTimeMismatch
   462  	} else if m1.StepTime == m2.StepTime {
   463  		err = mergeFetchResponsesWithEqualStepTimes(m1, m2)
   464  	} else {
   465  		err = mergeFetchResponsesWithUnequalStepTimes(m1, m2)
   466  	}
   467  
   468  	if err != nil {
   469  		zapwriter.Logger("zipper").Error("Unable to merge fetch responses",
   470  			zap.Error(err),
   471  			zap.Int64("m1_request_start_time", m1.RequestStartTime),
   472  			zap.Int64("m1_start_time", m1.StartTime),
   473  			zap.Int64("m1_stop_time", m1.StopTime),
   474  			zap.Int64("m1_step_time", m1.StepTime),
   475  			zap.Int64("m2_request_start_time", m2.RequestStartTime),
   476  			zap.Int64("m2_start_time", m2.StartTime),
   477  			zap.Int64("m2_stop_time", m2.StopTime),
   478  			zap.Int64("m2_step_time", m2.StepTime),
   479  		)
   480  	}
   481  
   482  	return err
   483  }
   484  
   485  type fetchResponseCoordinates struct {
   486  	name  string
   487  	from  int64
   488  	until int64
   489  }
   490  
   491  func coordinates(r *protov3.FetchResponse) fetchResponseCoordinates {
   492  	return fetchResponseCoordinates{
   493  		name:  r.Name,
   494  		from:  r.RequestStartTime,
   495  		until: r.RequestStopTime,
   496  	}
   497  }
   498  
   499  type ServerResponse struct {
   500  	Server   string
   501  	Response []byte
   502  }