github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/metrics/metadata/metadata.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package metadata 22 23 import ( 24 "bytes" 25 "fmt" 26 "strings" 27 28 "github.com/m3db/m3/src/metrics/aggregation" 29 "github.com/m3db/m3/src/metrics/generated/proto/metricpb" 30 "github.com/m3db/m3/src/metrics/generated/proto/policypb" 31 "github.com/m3db/m3/src/metrics/metric" 32 "github.com/m3db/m3/src/metrics/pipeline/applied" 33 "github.com/m3db/m3/src/metrics/policy" 34 "github.com/m3db/m3/src/query/models" 35 ) 36 37 var ( 38 // DefaultPipelineMetadata is a default pipeline metadata. 39 DefaultPipelineMetadata PipelineMetadata 40 41 // DefaultPipelineMetadatas is a default list of pipeline metadatas. 42 DefaultPipelineMetadatas = PipelineMetadatas{DefaultPipelineMetadata} 43 44 // DefaultMetadata is a default metadata. 45 DefaultMetadata = Metadata{Pipelines: DefaultPipelineMetadatas} 46 47 // DefaultStagedMetadata is a default staged metadata. 48 DefaultStagedMetadata = StagedMetadata{Metadata: DefaultMetadata} 49 50 // DefaultStagedMetadatas represents default staged metadatas. 51 DefaultStagedMetadatas = StagedMetadatas{DefaultStagedMetadata} 52 53 // DropPipelineMetadata is the drop policy pipeline metadata. 54 DropPipelineMetadata = PipelineMetadata{DropPolicy: policy.DropMust} 55 56 // DropPipelineMetadatas is the drop policy list of pipeline metadatas. 57 DropPipelineMetadatas = []PipelineMetadata{DropPipelineMetadata} 58 59 // DropIfOnlyMatchPipelineMetadata is the drop if only match policy 60 // pipeline metadata. 61 DropIfOnlyMatchPipelineMetadata = PipelineMetadata{DropPolicy: policy.DropIfOnlyMatch} 62 63 // DropIfOnlyMatchPipelineMetadatas is the drop if only match policy list 64 // of pipeline metadatas. 65 DropIfOnlyMatchPipelineMetadatas = []PipelineMetadata{DropIfOnlyMatchPipelineMetadata} 66 67 // DropMetadata is the drop policy metadata. 68 DropMetadata = Metadata{Pipelines: DropPipelineMetadatas} 69 70 // DropStagedMetadata is the drop policy staged metadata. 71 DropStagedMetadata = StagedMetadata{Metadata: DropMetadata} 72 73 // DropStagedMetadatas is the drop policy staged metadatas. 74 DropStagedMetadatas = StagedMetadatas{DropStagedMetadata} 75 ) 76 77 // PipelineMetadata contains pipeline metadata. 78 type PipelineMetadata struct { 79 // List of storage policies. 80 StoragePolicies policy.StoragePolicies `json:"storagePolicies,omitempty"` 81 // Pipeline operations. 82 Pipeline applied.Pipeline `json:"-"` 83 // Tags. 84 Tags []models.Tag `json:"tags,omitempty"` 85 // GraphitePrefix is the list of graphite prefixes to apply. 86 GraphitePrefix [][]byte `json:"graphitePrefix,omitempty"` 87 // List of aggregation types. 88 AggregationID aggregation.ID `json:"aggregation,omitempty"` 89 // Drop policy. 90 DropPolicy policy.DropPolicy `json:"dropPolicy,omitempty"` 91 // ResendEnabled is true if the Pipeline supports resending aggregate values after the initial flush. 92 ResendEnabled bool `json:"resendEnabled,omitempty"` 93 } 94 95 func (m PipelineMetadata) String() string { 96 var b bytes.Buffer 97 b.WriteString(fmt.Sprintf("ResendEnabled: %v, StoragePolicies: %v, Pipeline: %v", 98 m.ResendEnabled, m.StoragePolicies, m.Pipeline)) 99 return b.String() 100 } 101 102 // Equal returns true if two pipeline metadata are considered equal. 103 func (m PipelineMetadata) Equal(other PipelineMetadata) bool { 104 return m.AggregationID.Equal(other.AggregationID) && 105 m.StoragePolicies.Equal(other.StoragePolicies) && 106 m.Pipeline.Equal(other.Pipeline) && 107 m.DropPolicy == other.DropPolicy && 108 m.ResendEnabled == other.ResendEnabled 109 } 110 111 // IsDefault returns whether this is the default standard pipeline metadata. 112 func (m PipelineMetadata) IsDefault() bool { 113 return m.AggregationID == aggregation.DefaultID && 114 len(m.StoragePolicies) == 0 && 115 m.Pipeline.IsEmpty() && 116 m.DropPolicy == policy.DefaultDropPolicy && 117 !m.ResendEnabled 118 } 119 120 // IsMappingRule returns whether this is a mapping rule. 121 // nolint:gocritic 122 func (m PipelineMetadata) IsMappingRule() bool { 123 return m.Pipeline.IsMappingRule() 124 } 125 126 // IsAnyRollupRules returns whether any of the rules have rollups. 127 func (m PipelineMetadata) IsAnyRollupRules() bool { 128 return !m.Pipeline.IsMappingRule() 129 } 130 131 // IsDropPolicyApplied returns whether this is the default standard pipeline 132 // but with the drop policy applied. 133 func (m PipelineMetadata) IsDropPolicyApplied() bool { 134 return m.AggregationID.IsDefault() && 135 m.StoragePolicies.IsDefault() && 136 m.Pipeline.IsEmpty() && 137 m.IsDropPolicySet() 138 } 139 140 // IsDropPolicySet returns whether a drop policy is set. 141 func (m PipelineMetadata) IsDropPolicySet() bool { 142 return !m.DropPolicy.IsDefault() 143 } 144 145 // Clone clones the pipeline metadata. 146 func (m PipelineMetadata) Clone() PipelineMetadata { 147 return PipelineMetadata{ 148 AggregationID: m.AggregationID, 149 StoragePolicies: m.StoragePolicies.Clone(), 150 Pipeline: m.Pipeline.Clone(), 151 ResendEnabled: m.ResendEnabled, 152 } 153 } 154 155 // ToProto converts the pipeline metadata to a protobuf message in place. 156 func (m PipelineMetadata) ToProto(pb *metricpb.PipelineMetadata) error { 157 m.AggregationID.ToProto(&pb.AggregationId) 158 if err := m.Pipeline.ToProto(&pb.Pipeline); err != nil { 159 return err 160 } 161 numStoragePolicies := len(m.StoragePolicies) 162 if cap(pb.StoragePolicies) >= numStoragePolicies { 163 pb.StoragePolicies = pb.StoragePolicies[:numStoragePolicies] 164 } else { 165 pb.StoragePolicies = make([]policypb.StoragePolicy, numStoragePolicies) 166 } 167 for i := 0; i < numStoragePolicies; i++ { 168 if err := m.StoragePolicies[i].ToProto(&pb.StoragePolicies[i]); err != nil { 169 return err 170 } 171 } 172 pb.DropPolicy = policypb.DropPolicy(m.DropPolicy) 173 pb.ResendEnabled = m.ResendEnabled 174 return nil 175 } 176 177 // FromProto converts the protobuf message to a pipeline metadata in place. 178 func (m *PipelineMetadata) FromProto(pb metricpb.PipelineMetadata) error { 179 m.AggregationID.FromProto(pb.AggregationId) 180 if err := m.Pipeline.FromProto(pb.Pipeline); err != nil { 181 return err 182 } 183 numStoragePolicies := len(pb.StoragePolicies) 184 if cap(m.StoragePolicies) >= numStoragePolicies { 185 m.StoragePolicies = m.StoragePolicies[:numStoragePolicies] 186 } else { 187 m.StoragePolicies = make([]policy.StoragePolicy, numStoragePolicies) 188 } 189 for i := 0; i < numStoragePolicies; i++ { 190 if err := m.StoragePolicies[i].FromProto(pb.StoragePolicies[i]); err != nil { 191 return err 192 } 193 } 194 m.DropPolicy = policy.DropPolicy(pb.DropPolicy) 195 m.ResendEnabled = pb.ResendEnabled 196 return nil 197 } 198 199 // PipelineMetadatas is a list of pipeline metadatas. 200 type PipelineMetadatas []PipelineMetadata 201 202 // Equal returns true if two pipline metadatas are considered equal. 203 func (metadatas PipelineMetadatas) Equal(other PipelineMetadatas) bool { 204 if len(metadatas) != len(other) { 205 return false 206 } 207 for i := 0; i < len(metadatas); i++ { 208 if !metadatas[i].Equal(other[i]) { 209 return false 210 } 211 } 212 return true 213 } 214 215 // Len returns the number of pipelines in the metadata. 216 func (metadatas PipelineMetadatas) Len() int { return len(metadatas) } 217 218 // Swap swaps the elements with indexes i and j. 219 func (metadatas PipelineMetadatas) Swap(i, j int) { 220 metadatas[i], metadatas[j] = metadatas[j], metadatas[i] 221 } 222 223 // Less returns whether the element with 224 // index i should sort before the element with index j. 225 func (metadatas PipelineMetadatas) Less(i, j int) bool { 226 return strings.Compare(metadatas[i].String(), metadatas[j].String()) == -1 227 } 228 229 // Clone clones the list of pipeline metadatas. 230 func (metadatas PipelineMetadatas) Clone() PipelineMetadatas { 231 cloned := make(PipelineMetadatas, 0, len(metadatas)) 232 for i := 0; i < len(metadatas); i++ { 233 cloned = append(cloned, metadatas[i].Clone()) 234 } 235 return cloned 236 } 237 238 // IsDropPolicySet returns whether any drop policies are set (but 239 // does not discriminate if they have been applied or not). 240 func (metadatas PipelineMetadatas) IsDropPolicySet() bool { 241 for i := range metadatas { 242 if metadatas[i].IsDropPolicySet() { 243 return true 244 } 245 } 246 return false 247 } 248 249 // ApplyOrRemoveDropPoliciesResult is the result of applying or removing 250 // the drop policies for pipelines. 251 type ApplyOrRemoveDropPoliciesResult uint 252 253 const ( 254 // NoDropPolicyPresentResult is the result of no drop policies being present. 255 NoDropPolicyPresentResult ApplyOrRemoveDropPoliciesResult = iota 256 // AppliedEffectiveDropPolicyResult is the result of applying the drop 257 // policy and returning just the single drop policy pipeline. 258 AppliedEffectiveDropPolicyResult 259 // RemovedIneffectiveDropPoliciesResult is the result of no drop policies 260 // being effective and returning the pipelines without any drop policies. 261 RemovedIneffectiveDropPoliciesResult 262 ) 263 264 // ApplyOrRemoveDropPolicies applies or removes any drop policies, if 265 // effective then just the drop pipeline is returned otherwise if not 266 // effective it returns the drop policy pipelines that were not effective. 267 func (metadatas PipelineMetadatas) ApplyOrRemoveDropPolicies() ( 268 PipelineMetadatas, 269 ApplyOrRemoveDropPoliciesResult, 270 ) { 271 // Check drop policies 272 dropIfOnlyMatchPipelines := 0 273 nonDropPipelines := 0 274 for i := range metadatas { 275 switch metadatas[i].DropPolicy { 276 case policy.DropMust: 277 // Immediately return, result is a drop 278 return DropPipelineMetadatas, AppliedEffectiveDropPolicyResult 279 case policy.DropIfOnlyMatch: 280 dropIfOnlyMatchPipelines++ 281 continue 282 } 283 nonDropPipelines++ 284 } 285 286 if dropIfOnlyMatchPipelines == 0 { 287 // No drop if only match pipelines, no need to remove anything 288 return metadatas, NoDropPolicyPresentResult 289 } 290 291 result := metadatas 292 293 // Drop is effective as no other non drop pipelines, result is a drop 294 if nonDropPipelines == 0 { 295 // nb: Do not directly return DropPipelineMetadatas, as the client could potentially save that reference 296 // and modify global state. 297 result = result[:0] 298 result = append(result, DropPipelineMetadata) 299 return result, AppliedEffectiveDropPolicyResult 300 } 301 302 // Remove all non-default drop policies as they must not be effective 303 for i := len(result) - 1; i >= 0; i-- { 304 if !result[i].DropPolicy.IsDefault() { 305 // Remove by moving to tail and decrementing length so we can do in 306 // place to avoid allocations of a new slice 307 if lastElem := i == len(result)-1; lastElem { 308 result = result[0:i] 309 } else { 310 result = append(result[0:i], result[i+1:]...) 311 } 312 } 313 } 314 315 return result, RemovedIneffectiveDropPoliciesResult 316 } 317 318 // ShouldDropTimestampOptions are options for the should drop timestamp method. 319 type ShouldDropTimestampOptions struct { 320 UntimedRollups bool 321 } 322 323 // ShouldDropTimestamp applies custom M3 tags. 324 func (metadatas PipelineMetadatas) ShouldDropTimestamp(opts ShouldDropTimestampOptions) bool { 325 // Go over metadatas and and look for drop timestamp tag. 326 for i := range metadatas { 327 if opts.UntimedRollups { 328 if metadatas[i].IsAnyRollupRules() { 329 return true 330 } 331 } 332 for j := range metadatas[i].Tags { 333 // If any metadata has the drop timestamp tag, then return that we 334 // should send untimed metrics to the aggregator. 335 if bytes.Equal(metadatas[i].Tags[j].Name, metric.M3MetricsDropTimestamp) { 336 return true 337 } 338 } 339 } 340 return false 341 } 342 343 // Metadata represents the metadata associated with a metric. 344 type Metadata struct { 345 Pipelines PipelineMetadatas `json:"pipelines,omitempty"` 346 } 347 348 // IsDefault returns whether this is the default metadata. 349 func (m Metadata) IsDefault() bool { 350 return len(m.Pipelines) == 1 && m.Pipelines[0].IsDefault() 351 } 352 353 // IsDropPolicyApplied returns whether this is the default metadata 354 // but with the drop policy applied. 355 func (m Metadata) IsDropPolicyApplied() bool { 356 return len(m.Pipelines) == 1 && m.Pipelines[0].IsDropPolicyApplied() 357 } 358 359 // IsDropPolicySet returns whether any drop policies are set (but 360 // does not discriminate if they have been applied or not). 361 func (m Metadata) IsDropPolicySet() bool { 362 for i := range m.Pipelines { 363 if m.Pipelines[i].IsDropPolicySet() { 364 return true 365 } 366 } 367 return false 368 } 369 370 // Equal returns true if two metadatas are considered equal. 371 func (m Metadata) Equal(other Metadata) bool { 372 return m.Pipelines.Equal(other.Pipelines) 373 } 374 375 // ToProto converts the metadata to a protobuf message in place. 376 func (m Metadata) ToProto(pb *metricpb.Metadata) error { 377 numPipelines := len(m.Pipelines) 378 if cap(pb.Pipelines) >= numPipelines { 379 pb.Pipelines = pb.Pipelines[:numPipelines] 380 } else { 381 pb.Pipelines = make([]metricpb.PipelineMetadata, numPipelines) 382 } 383 for i := 0; i < numPipelines; i++ { 384 if err := m.Pipelines[i].ToProto(&pb.Pipelines[i]); err != nil { 385 return err 386 } 387 } 388 return nil 389 } 390 391 // FromProto converts the protobuf message to a metadata in place. 392 func (m *Metadata) FromProto(pb metricpb.Metadata) error { 393 numPipelines := len(pb.Pipelines) 394 if cap(m.Pipelines) >= numPipelines { 395 m.Pipelines = m.Pipelines[:numPipelines] 396 } else { 397 m.Pipelines = make(PipelineMetadatas, numPipelines) 398 } 399 for i := 0; i < numPipelines; i++ { 400 if err := m.Pipelines[i].FromProto(pb.Pipelines[i]); err != nil { 401 return err 402 } 403 } 404 return nil 405 } 406 407 // ForwardMetadata represents the metadata information associated with forwarded metrics. 408 type ForwardMetadata struct { 409 // Pipeline of operations that may be applied to the metric. 410 Pipeline applied.Pipeline 411 // Storage policy. 412 StoragePolicy policy.StoragePolicy 413 // List of aggregation types. 414 AggregationID aggregation.ID 415 // Number of times this metric has been forwarded. 416 NumForwardedTimes int 417 // Metric source id that refers to the unique id of the source producing this metric. 418 SourceID uint32 419 // ResendEnabled is true if the Pipeline supports resending aggregate values after the initial flush. 420 ResendEnabled bool 421 } 422 423 // ToProto converts the forward metadata to a protobuf message in place. 424 func (m ForwardMetadata) ToProto(pb *metricpb.ForwardMetadata) error { 425 m.AggregationID.ToProto(&pb.AggregationId) 426 if err := m.StoragePolicy.ToProto(&pb.StoragePolicy); err != nil { 427 return err 428 } 429 if err := m.Pipeline.ToProto(&pb.Pipeline); err != nil { 430 return err 431 } 432 pb.SourceId = m.SourceID 433 pb.NumForwardedTimes = int32(m.NumForwardedTimes) 434 pb.ResendEnabled = m.ResendEnabled 435 return nil 436 } 437 438 // FromProto converts the protobuf message to a forward metadata in place. 439 func (m *ForwardMetadata) FromProto(pb metricpb.ForwardMetadata) error { 440 m.AggregationID.FromProto(pb.AggregationId) 441 if err := m.StoragePolicy.FromProto(pb.StoragePolicy); err != nil { 442 return err 443 } 444 if err := m.Pipeline.FromProto(pb.Pipeline); err != nil { 445 return err 446 } 447 m.SourceID = pb.SourceId 448 m.NumForwardedTimes = int(pb.NumForwardedTimes) 449 m.ResendEnabled = pb.ResendEnabled 450 return nil 451 } 452 453 // StagedMetadata represents metadata with a staged cutover time. 454 type StagedMetadata struct { 455 Metadata `json:"metadata,omitempty"` 456 457 // Cutover is when the metadata is applicable. 458 CutoverNanos int64 `json:"cutoverNanos,omitempty"` 459 460 // Tombstoned determines whether the associated metric has been tombstoned. 461 Tombstoned bool `json:"tombstoned,omitempty"` 462 } 463 464 // Equal returns true if two staged metadatas are considered equal. 465 func (sm StagedMetadata) Equal(other StagedMetadata) bool { 466 return sm.Metadata.Equal(other.Metadata) && 467 sm.CutoverNanos == other.CutoverNanos && 468 sm.Tombstoned == other.Tombstoned 469 } 470 471 // IsDefault returns whether this is a default staged metadata. 472 func (sm StagedMetadata) IsDefault() bool { 473 return sm.CutoverNanos == 0 && !sm.Tombstoned && sm.Metadata.IsDefault() 474 } 475 476 // IsDropPolicyApplied returns whether this is the default staged metadata 477 // but with the drop policy applied. 478 func (sm StagedMetadata) IsDropPolicyApplied() bool { 479 return !sm.Tombstoned && sm.Metadata.IsDropPolicyApplied() 480 } 481 482 // IsDropPolicySet returns whether a drop policy is set. 483 func (sm StagedMetadata) IsDropPolicySet() bool { 484 return sm.Pipelines.IsDropPolicySet() 485 } 486 487 // ToProto converts the staged metadata to a protobuf message in place. 488 func (sm StagedMetadata) ToProto(pb *metricpb.StagedMetadata) error { 489 if err := sm.Metadata.ToProto(&pb.Metadata); err != nil { 490 return err 491 } 492 pb.CutoverNanos = sm.CutoverNanos 493 pb.Tombstoned = sm.Tombstoned 494 return nil 495 } 496 497 // FromProto converts the protobuf message to a staged metadata in place. 498 func (sm *StagedMetadata) FromProto(pb metricpb.StagedMetadata) error { 499 if err := sm.Metadata.FromProto(pb.Metadata); err != nil { 500 return err 501 } 502 sm.CutoverNanos = pb.CutoverNanos 503 sm.Tombstoned = pb.Tombstoned 504 return nil 505 } 506 507 func (sm StagedMetadata) String() string { 508 var b bytes.Buffer 509 for _, p := range sm.Pipelines { 510 b.WriteString(p.String()) 511 } 512 return b.String() 513 } 514 515 // StagedMetadatas contains a list of staged metadatas. 516 type StagedMetadatas []StagedMetadata 517 518 // Equal returns true if two staged metadatas slices are considered equal. 519 func (sms StagedMetadatas) Equal(other StagedMetadatas) bool { 520 if len(sms) != len(other) { 521 return false 522 } 523 for i := range sms { 524 if !sms[i].Equal(other[i]) { 525 return false 526 } 527 } 528 return true 529 } 530 531 // IsDefault determines whether the list of staged metadata is a default list. 532 func (sms StagedMetadatas) IsDefault() bool { 533 // very ugly but need to help out the go compiler here, as function calls have a high inlining cost 534 return len(sms) == 1 && len(sms[0].Pipelines) == 1 && 535 sms[0].CutoverNanos == 0 && !sms[0].Tombstoned && 536 sms[0].Pipelines[0].AggregationID == aggregation.DefaultID && 537 len(sms[0].Pipelines[0].StoragePolicies) == 0 && 538 sms[0].Pipelines[0].Pipeline.IsEmpty() && 539 sms[0].Pipelines[0].DropPolicy == policy.DefaultDropPolicy 540 } 541 542 // IsDropPolicyApplied returns whether the list of staged metadata is the 543 // default list but with the drop policy applied. 544 func (sms StagedMetadatas) IsDropPolicyApplied() bool { 545 return len(sms) == 1 && sms[0].IsDropPolicyApplied() 546 } 547 548 // IsDropPolicySet returns if the active staged metadata has a drop policy set. 549 func (sms StagedMetadatas) IsDropPolicySet() bool { 550 return len(sms) > 0 && sms[len(sms)-1].IsDropPolicySet() 551 } 552 553 // ToProto converts the staged metadatas to a protobuf message in place. 554 func (sms StagedMetadatas) ToProto(pb *metricpb.StagedMetadatas) error { 555 numMetadatas := len(sms) 556 if cap(pb.Metadatas) >= numMetadatas { 557 pb.Metadatas = pb.Metadatas[:numMetadatas] 558 } else { 559 pb.Metadatas = make([]metricpb.StagedMetadata, numMetadatas) 560 } 561 for i := 0; i < numMetadatas; i++ { 562 if err := sms[i].ToProto(&pb.Metadatas[i]); err != nil { 563 return err 564 } 565 } 566 return nil 567 } 568 569 // FromProto converts the protobuf message to a staged metadatas in place. 570 // This is an optimized method that merges some nested steps. 571 func (sms *StagedMetadatas) FromProto(pb metricpb.StagedMetadatas) error { 572 numMetadatas := len(pb.Metadatas) 573 if cap(*sms) >= numMetadatas { 574 *sms = (*sms)[:numMetadatas] 575 } else { 576 *sms = make([]StagedMetadata, numMetadatas) 577 } 578 579 for i := 0; i < numMetadatas; i++ { 580 metadata := &(*sms)[i] 581 metadataPb := &pb.Metadatas[i] 582 numPipelines := len(metadataPb.Metadata.Pipelines) 583 584 metadata.CutoverNanos = metadataPb.CutoverNanos 585 metadata.Tombstoned = metadataPb.Tombstoned 586 587 if cap(metadata.Pipelines) >= numPipelines { 588 metadata.Pipelines = metadata.Pipelines[:numPipelines] 589 } else { 590 metadata.Pipelines = make(PipelineMetadatas, numPipelines) 591 } 592 593 for j := 0; j < numPipelines; j++ { 594 var ( 595 pipelinePb = &metadataPb.Metadata.Pipelines[j] 596 pipeline = &metadata.Pipelines[j] 597 numStoragePolicies = len(pipelinePb.StoragePolicies) 598 numOps = len(pipelinePb.Pipeline.Ops) 599 err error 600 ) 601 602 pipeline.AggregationID[0] = pipelinePb.AggregationId.Id 603 pipeline.DropPolicy = policy.DropPolicy(pipelinePb.DropPolicy) 604 pipeline.ResendEnabled = pipelinePb.ResendEnabled 605 606 if len(pipeline.Tags) > 0 { 607 pipeline.Tags = pipeline.Tags[:0] 608 } 609 if len(pipeline.GraphitePrefix) > 0 { 610 pipeline.GraphitePrefix = pipeline.GraphitePrefix[:0] 611 } 612 613 if cap(pipeline.StoragePolicies) >= numStoragePolicies { 614 pipeline.StoragePolicies = pipeline.StoragePolicies[:numStoragePolicies] 615 } else { 616 pipeline.StoragePolicies = make([]policy.StoragePolicy, numStoragePolicies) 617 } 618 619 if cap(pipeline.Pipeline.Operations) >= numOps { 620 pipeline.Pipeline.Operations = pipeline.Pipeline.Operations[:numOps] 621 } else { 622 pipeline.Pipeline.Operations = make([]applied.OpUnion, numOps) 623 } 624 625 if len(pipelinePb.Pipeline.Ops) > 0 { 626 err = applied.OperationsFromProto(pipelinePb.Pipeline.Ops, pipeline.Pipeline.Operations) 627 if err != nil { 628 return err 629 } 630 } 631 if len(pipelinePb.StoragePolicies) > 0 { 632 err = policy.StoragePoliciesFromProto(pipelinePb.StoragePolicies, pipeline.StoragePolicies) 633 if err != nil { 634 return err 635 } 636 } 637 } 638 } 639 640 return nil 641 } 642 643 // fromProto is a non-optimized in place protobuf conversion method, used as a reference for tests. 644 func (sms *StagedMetadatas) fromProto(pb metricpb.StagedMetadatas) error { 645 numMetadatas := len(pb.Metadatas) 646 if cap(*sms) >= numMetadatas { 647 *sms = (*sms)[:numMetadatas] 648 } else { 649 *sms = make([]StagedMetadata, numMetadatas) 650 } 651 for i := 0; i < numMetadatas; i++ { 652 if err := (*sms)[i].FromProto(pb.Metadatas[i]); err != nil { 653 return err 654 } 655 } 656 return nil 657 } 658 659 // VersionedStagedMetadatas is a versioned staged metadatas. 660 type VersionedStagedMetadatas struct { 661 StagedMetadatas StagedMetadatas `json:"stagedMetadatas"` 662 Version int `json:"version"` 663 } 664 665 // TimedMetadata represents the metadata information associated with timed metrics. 666 type TimedMetadata struct { 667 // List of aggregation types. 668 AggregationID aggregation.ID 669 670 // Storage policy. 671 StoragePolicy policy.StoragePolicy 672 } 673 674 // ToProto converts the timed metadata to a protobuf message in place. 675 func (m TimedMetadata) ToProto(pb *metricpb.TimedMetadata) error { 676 m.AggregationID.ToProto(&pb.AggregationId) 677 if err := m.StoragePolicy.ToProto(&pb.StoragePolicy); err != nil { 678 return err 679 } 680 return nil 681 } 682 683 // FromProto converts the protobuf message to a timed metadata in place. 684 func (m *TimedMetadata) FromProto(pb metricpb.TimedMetadata) error { 685 m.AggregationID.FromProto(pb.AggregationId) 686 if err := m.StoragePolicy.FromProto(pb.StoragePolicy); err != nil { 687 return err 688 } 689 return nil 690 }