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 }