1// Package models implements basic objects used throughout the TICK stack. 2package models // import "github.com/influxdata/influxdb/models" 3 4import ( 5 "bytes" 6 "encoding/binary" 7 "errors" 8 "fmt" 9 "io" 10 "math" 11 "sort" 12 "strconv" 13 "strings" 14 "time" 15 "unicode" 16 "unicode/utf8" 17 18 "github.com/influxdata/influxdb/pkg/escape" 19) 20 21// Values used to store the field key and measurement name as special internal 22// tags. 23const ( 24 FieldKeyTagKey = "\xff" 25 MeasurementTagKey = "\x00" 26) 27 28// Predefined byte representations of special tag keys. 29var ( 30 FieldKeyTagKeyBytes = []byte(FieldKeyTagKey) 31 MeasurementTagKeyBytes = []byte(MeasurementTagKey) 32) 33 34type escapeSet struct { 35 k [1]byte 36 esc [2]byte 37} 38 39var ( 40 measurementEscapeCodes = [...]escapeSet{ 41 {k: [1]byte{','}, esc: [2]byte{'\\', ','}}, 42 {k: [1]byte{' '}, esc: [2]byte{'\\', ' '}}, 43 } 44 45 tagEscapeCodes = [...]escapeSet{ 46 {k: [1]byte{','}, esc: [2]byte{'\\', ','}}, 47 {k: [1]byte{' '}, esc: [2]byte{'\\', ' '}}, 48 {k: [1]byte{'='}, esc: [2]byte{'\\', '='}}, 49 } 50 51 // ErrPointMustHaveAField is returned when operating on a point that does not have any fields. 52 ErrPointMustHaveAField = errors.New("point without fields is unsupported") 53 54 // ErrInvalidNumber is returned when a number is expected but not provided. 55 ErrInvalidNumber = errors.New("invalid number") 56 57 // ErrInvalidPoint is returned when a point cannot be parsed correctly. 58 ErrInvalidPoint = errors.New("point is invalid") 59) 60 61const ( 62 // MaxKeyLength is the largest allowed size of the combined measurement and tag keys. 63 MaxKeyLength = 65535 64) 65 66// enableUint64Support will enable uint64 support if set to true. 67var enableUint64Support = false 68 69// EnableUintSupport manually enables uint support for the point parser. 70// This function will be removed in the future and only exists for unit tests during the 71// transition. 72func EnableUintSupport() { 73 enableUint64Support = true 74} 75 76// Point defines the values that will be written to the database. 77type Point interface { 78 // Name return the measurement name for the point. 79 Name() []byte 80 81 // SetName updates the measurement name for the point. 82 SetName(string) 83 84 // Tags returns the tag set for the point. 85 Tags() Tags 86 87 // ForEachTag iterates over each tag invoking fn. If fn return false, iteration stops. 88 ForEachTag(fn func(k, v []byte) bool) 89 90 // AddTag adds or replaces a tag value for a point. 91 AddTag(key, value string) 92 93 // SetTags replaces the tags for the point. 94 SetTags(tags Tags) 95 96 // HasTag returns true if the tag exists for the point. 97 HasTag(tag []byte) bool 98 99 // Fields returns the fields for the point. 100 Fields() (Fields, error) 101 102 // Time return the timestamp for the point. 103 Time() time.Time 104 105 // SetTime updates the timestamp for the point. 106 SetTime(t time.Time) 107 108 // UnixNano returns the timestamp of the point as nanoseconds since Unix epoch. 109 UnixNano() int64 110 111 // HashID returns a non-cryptographic checksum of the point's key. 112 HashID() uint64 113 114 // Key returns the key (measurement joined with tags) of the point. 115 Key() []byte 116 117 // String returns a string representation of the point. If there is a 118 // timestamp associated with the point then it will be specified with the default 119 // precision of nanoseconds. 120 String() string 121 122 // MarshalBinary returns a binary representation of the point. 123 MarshalBinary() ([]byte, error) 124 125 // PrecisionString returns a string representation of the point. If there 126 // is a timestamp associated with the point then it will be specified in the 127 // given unit. 128 PrecisionString(precision string) string 129 130 // RoundedString returns a string representation of the point. If there 131 // is a timestamp associated with the point, then it will be rounded to the 132 // given duration. 133 RoundedString(d time.Duration) string 134 135 // Split will attempt to return multiple points with the same timestamp whose 136 // string representations are no longer than size. Points with a single field or 137 // a point without a timestamp may exceed the requested size. 138 Split(size int) []Point 139 140 // Round will round the timestamp of the point to the given duration. 141 Round(d time.Duration) 142 143 // StringSize returns the length of the string that would be returned by String(). 144 StringSize() int 145 146 // AppendString appends the result of String() to the provided buffer and returns 147 // the result, potentially reducing string allocations. 148 AppendString(buf []byte) []byte 149 150 // FieldIterator returns a FieldIterator that can be used to traverse the 151 // fields of a point without constructing the in-memory map. 152 FieldIterator() FieldIterator 153} 154 155// FieldType represents the type of a field. 156type FieldType int 157 158const ( 159 // Integer indicates the field's type is integer. 160 Integer FieldType = iota 161 162 // Float indicates the field's type is float. 163 Float 164 165 // Boolean indicates the field's type is boolean. 166 Boolean 167 168 // String indicates the field's type is string. 169 String 170 171 // Empty is used to indicate that there is no field. 172 Empty 173 174 // Unsigned indicates the field's type is an unsigned integer. 175 Unsigned 176) 177 178// FieldIterator provides a low-allocation interface to iterate through a point's fields. 179type FieldIterator interface { 180 // Next indicates whether there any fields remaining. 181 Next() bool 182 183 // FieldKey returns the key of the current field. 184 FieldKey() []byte 185 186 // Type returns the FieldType of the current field. 187 Type() FieldType 188 189 // StringValue returns the string value of the current field. 190 StringValue() string 191 192 // IntegerValue returns the integer value of the current field. 193 IntegerValue() (int64, error) 194 195 // UnsignedValue returns the unsigned value of the current field. 196 UnsignedValue() (uint64, error) 197 198 // BooleanValue returns the boolean value of the current field. 199 BooleanValue() (bool, error) 200 201 // FloatValue returns the float value of the current field. 202 FloatValue() (float64, error) 203 204 // Reset resets the iterator to its initial state. 205 Reset() 206} 207 208// Points represents a sortable list of points by timestamp. 209type Points []Point 210 211// Len implements sort.Interface. 212func (a Points) Len() int { return len(a) } 213 214// Less implements sort.Interface. 215func (a Points) Less(i, j int) bool { return a[i].Time().Before(a[j].Time()) } 216 217// Swap implements sort.Interface. 218func (a Points) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 219 220// point is the default implementation of Point. 221type point struct { 222 time time.Time 223 224 // text encoding of measurement and tags 225 // key must always be stored sorted by tags, if the original line was not sorted, 226 // we need to resort it 227 key []byte 228 229 // text encoding of field data 230 fields []byte 231 232 // text encoding of timestamp 233 ts []byte 234 235 // cached version of parsed fields from data 236 cachedFields map[string]interface{} 237 238 // cached version of parsed name from key 239 cachedName string 240 241 // cached version of parsed tags 242 cachedTags Tags 243 244 it fieldIterator 245} 246 247// type assertions 248var ( 249 _ Point = (*point)(nil) 250 _ FieldIterator = (*point)(nil) 251) 252 253const ( 254 // the number of characters for the largest possible int64 (9223372036854775807) 255 maxInt64Digits = 19 256 257 // the number of characters for the smallest possible int64 (-9223372036854775808) 258 minInt64Digits = 20 259 260 // the number of characters for the largest possible uint64 (18446744073709551615) 261 maxUint64Digits = 20 262 263 // the number of characters required for the largest float64 before a range check 264 // would occur during parsing 265 maxFloat64Digits = 25 266 267 // the number of characters required for smallest float64 before a range check occur 268 // would occur during parsing 269 minFloat64Digits = 27 270) 271 272// ParsePoints returns a slice of Points from a text representation of a point 273// with each point separated by newlines. If any points fail to parse, a non-nil error 274// will be returned in addition to the points that parsed successfully. 275func ParsePoints(buf []byte) ([]Point, error) { 276 return ParsePointsWithPrecision(buf, time.Now().UTC(), "n") 277} 278 279// ParsePointsString is identical to ParsePoints but accepts a string. 280func ParsePointsString(buf string) ([]Point, error) { 281 return ParsePoints([]byte(buf)) 282} 283 284// ParseKey returns the measurement name and tags from a point. 285// 286// NOTE: to minimize heap allocations, the returned Tags will refer to subslices of buf. 287// This can have the unintended effect preventing buf from being garbage collected. 288func ParseKey(buf []byte) (string, Tags) { 289 name, tags := ParseKeyBytes(buf) 290 return string(name), tags 291} 292 293func ParseKeyBytes(buf []byte) ([]byte, Tags) { 294 return ParseKeyBytesWithTags(buf, nil) 295} 296 297func ParseKeyBytesWithTags(buf []byte, tags Tags) ([]byte, Tags) { 298 // Ignore the error because scanMeasurement returns "missing fields" which we ignore 299 // when just parsing a key 300 state, i, _ := scanMeasurement(buf, 0) 301 302 var name []byte 303 if state == tagKeyState { 304 tags = parseTags(buf, tags) 305 // scanMeasurement returns the location of the comma if there are tags, strip that off 306 name = buf[:i-1] 307 } else { 308 name = buf[:i] 309 } 310 return unescapeMeasurement(name), tags 311} 312 313func ParseTags(buf []byte) Tags { 314 return parseTags(buf, nil) 315} 316 317func ParseName(buf []byte) []byte { 318 // Ignore the error because scanMeasurement returns "missing fields" which we ignore 319 // when just parsing a key 320 state, i, _ := scanMeasurement(buf, 0) 321 var name []byte 322 if state == tagKeyState { 323 name = buf[:i-1] 324 } else { 325 name = buf[:i] 326 } 327 328 return unescapeMeasurement(name) 329} 330 331// ParsePointsWithPrecision is similar to ParsePoints, but allows the 332// caller to provide a precision for time. 333// 334// NOTE: to minimize heap allocations, the returned Points will refer to subslices of buf. 335// This can have the unintended effect preventing buf from being garbage collected. 336func ParsePointsWithPrecision(buf []byte, defaultTime time.Time, precision string) ([]Point, error) { 337 points := make([]Point, 0, bytes.Count(buf, []byte{'\n'})+1) 338 var ( 339 pos int 340 block []byte 341 failed []string 342 ) 343 for pos < len(buf) { 344 pos, block = scanLine(buf, pos) 345 pos++ 346 347 if len(block) == 0 { 348 continue 349 } 350 351 start := skipWhitespace(block, 0) 352 353 // If line is all whitespace, just skip it 354 if start >= len(block) { 355 continue 356 } 357 358 // lines which start with '#' are comments 359 if block[start] == '#' { 360 continue 361 } 362 363 // strip the newline if one is present 364 if block[len(block)-1] == '\n' { 365 block = block[:len(block)-1] 366 } 367 368 pt, err := parsePoint(block[start:], defaultTime, precision) 369 if err != nil { 370 failed = append(failed, fmt.Sprintf("unable to parse '%s': %v", string(block[start:]), err)) 371 } else { 372 points = append(points, pt) 373 } 374 375 } 376 if len(failed) > 0 { 377 return points, fmt.Errorf("%s", strings.Join(failed, "\n")) 378 } 379 return points, nil 380 381} 382 383func parsePoint(buf []byte, defaultTime time.Time, precision string) (Point, error) { 384 // scan the first block which is measurement[,tag1=value1,tag2=value2...] 385 pos, key, err := scanKey(buf, 0) 386 if err != nil { 387 return nil, err 388 } 389 390 // measurement name is required 391 if len(key) == 0 { 392 return nil, fmt.Errorf("missing measurement") 393 } 394 395 if len(key) > MaxKeyLength { 396 return nil, fmt.Errorf("max key length exceeded: %v > %v", len(key), MaxKeyLength) 397 } 398 399 // scan the second block is which is field1=value1[,field2=value2,...] 400 pos, fields, err := scanFields(buf, pos) 401 if err != nil { 402 return nil, err 403 } 404 405 // at least one field is required 406 if len(fields) == 0 { 407 return nil, fmt.Errorf("missing fields") 408 } 409 410 var maxKeyErr error 411 err = walkFields(fields, func(k, v []byte) bool { 412 if sz := seriesKeySize(key, k); sz > MaxKeyLength { 413 maxKeyErr = fmt.Errorf("max key length exceeded: %v > %v", sz, MaxKeyLength) 414 return false 415 } 416 return true 417 }) 418 419 if err != nil { 420 return nil, err 421 } 422 423 if maxKeyErr != nil { 424 return nil, maxKeyErr 425 } 426 427 // scan the last block which is an optional integer timestamp 428 pos, ts, err := scanTime(buf, pos) 429 if err != nil { 430 return nil, err 431 } 432 433 pt := &point{ 434 key: key, 435 fields: fields, 436 ts: ts, 437 } 438 439 if len(ts) == 0 { 440 pt.time = defaultTime 441 pt.SetPrecision(precision) 442 } else { 443 ts, err := parseIntBytes(ts, 10, 64) 444 if err != nil { 445 return nil, err 446 } 447 pt.time, err = SafeCalcTime(ts, precision) 448 if err != nil { 449 return nil, err 450 } 451 452 // Determine if there are illegal non-whitespace characters after the 453 // timestamp block. 454 for pos < len(buf) { 455 if buf[pos] != ' ' { 456 return nil, ErrInvalidPoint 457 } 458 pos++ 459 } 460 } 461 return pt, nil 462} 463 464// GetPrecisionMultiplier will return a multiplier for the precision specified. 465func GetPrecisionMultiplier(precision string) int64 { 466 d := time.Nanosecond 467 switch precision { 468 case "u": 469 d = time.Microsecond 470 case "ms": 471 d = time.Millisecond 472 case "s": 473 d = time.Second 474 case "m": 475 d = time.Minute 476 case "h": 477 d = time.Hour 478 } 479 return int64(d) 480} 481 482// scanKey scans buf starting at i for the measurement and tag portion of the point. 483// It returns the ending position and the byte slice of key within buf. If there 484// are tags, they will be sorted if they are not already. 485func scanKey(buf []byte, i int) (int, []byte, error) { 486 start := skipWhitespace(buf, i) 487 488 i = start 489 490 // Determines whether the tags are sort, assume they are 491 sorted := true 492 493 // indices holds the indexes within buf of the start of each tag. For example, 494 // a buf of 'cpu,host=a,region=b,zone=c' would have indices slice of [4,11,20] 495 // which indicates that the first tag starts at buf[4], seconds at buf[11], and 496 // last at buf[20] 497 indices := make([]int, 100) 498 499 // tracks how many commas we've seen so we know how many values are indices. 500 // Since indices is an arbitrarily large slice, 501 // we need to know how many values in the buffer are in use. 502 commas := 0 503 504 // First scan the Point's measurement. 505 state, i, err := scanMeasurement(buf, i) 506 if err != nil { 507 return i, buf[start:i], err 508 } 509 510 // Optionally scan tags if needed. 511 if state == tagKeyState { 512 i, commas, indices, err = scanTags(buf, i, indices) 513 if err != nil { 514 return i, buf[start:i], err 515 } 516 } 517 518 // Now we know where the key region is within buf, and the location of tags, we 519 // need to determine if duplicate tags exist and if the tags are sorted. This iterates 520 // over the list comparing each tag in the sequence with each other. 521 for j := 0; j < commas-1; j++ { 522 // get the left and right tags 523 _, left := scanTo(buf[indices[j]:indices[j+1]-1], 0, '=') 524 _, right := scanTo(buf[indices[j+1]:indices[j+2]-1], 0, '=') 525 526 // If left is greater than right, the tags are not sorted. We do not have to 527 // continue because the short path no longer works. 528 // If the tags are equal, then there are duplicate tags, and we should abort. 529 // If the tags are not sorted, this pass may not find duplicate tags and we 530 // need to do a more exhaustive search later. 531 if cmp := bytes.Compare(left, right); cmp > 0 { 532 sorted = false 533 break 534 } else if cmp == 0 { 535 return i, buf[start:i], fmt.Errorf("duplicate tags") 536 } 537 } 538 539 // If the tags are not sorted, then sort them. This sort is inline and 540 // uses the tag indices we created earlier. The actual buffer is not sorted, the 541 // indices are using the buffer for value comparison. After the indices are sorted, 542 // the buffer is reconstructed from the sorted indices. 543 if !sorted && commas > 0 { 544 // Get the measurement name for later 545 measurement := buf[start : indices[0]-1] 546 547 // Sort the indices 548 indices := indices[:commas] 549 insertionSort(0, commas, buf, indices) 550 551 // Create a new key using the measurement and sorted indices 552 b := make([]byte, len(buf[start:i])) 553 pos := copy(b, measurement) 554 for _, i := range indices { 555 b[pos] = ',' 556 pos++ 557 _, v := scanToSpaceOr(buf, i, ',') 558 pos += copy(b[pos:], v) 559 } 560 561 // Check again for duplicate tags now that the tags are sorted. 562 for j := 0; j < commas-1; j++ { 563 // get the left and right tags 564 _, left := scanTo(buf[indices[j]:], 0, '=') 565 _, right := scanTo(buf[indices[j+1]:], 0, '=') 566 567 // If the tags are equal, then there are duplicate tags, and we should abort. 568 // If the tags are not sorted, this pass may not find duplicate tags and we 569 // need to do a more exhaustive search later. 570 if bytes.Equal(left, right) { 571 return i, b, fmt.Errorf("duplicate tags") 572 } 573 } 574 575 return i, b, nil 576 } 577 578 return i, buf[start:i], nil 579} 580 581// The following constants allow us to specify which state to move to 582// next, when scanning sections of a Point. 583const ( 584 tagKeyState = iota 585 tagValueState 586 fieldsState 587) 588 589// scanMeasurement examines the measurement part of a Point, returning 590// the next state to move to, and the current location in the buffer. 591func scanMeasurement(buf []byte, i int) (int, int, error) { 592 // Check first byte of measurement, anything except a comma is fine. 593 // It can't be a space, since whitespace is stripped prior to this 594 // function call. 595 if i >= len(buf) || buf[i] == ',' { 596 return -1, i, fmt.Errorf("missing measurement") 597 } 598 599 for { 600 i++ 601 if i >= len(buf) { 602 // cpu 603 return -1, i, fmt.Errorf("missing fields") 604 } 605 606 if buf[i-1] == '\\' { 607 // Skip character (it's escaped). 608 continue 609 } 610 611 // Unescaped comma; move onto scanning the tags. 612 if buf[i] == ',' { 613 return tagKeyState, i + 1, nil 614 } 615 616 // Unescaped space; move onto scanning the fields. 617 if buf[i] == ' ' { 618 // cpu value=1.0 619 return fieldsState, i, nil 620 } 621 } 622} 623 624// scanTags examines all the tags in a Point, keeping track of and 625// returning the updated indices slice, number of commas and location 626// in buf where to start examining the Point fields. 627func scanTags(buf []byte, i int, indices []int) (int, int, []int, error) { 628 var ( 629 err error 630 commas int 631 state = tagKeyState 632 ) 633 634 for { 635 switch state { 636 case tagKeyState: 637 // Grow our indices slice if we have too many tags. 638 if commas >= len(indices) { 639 newIndics := make([]int, cap(indices)*2) 640 copy(newIndics, indices) 641 indices = newIndics 642 } 643 indices[commas] = i 644 commas++ 645 646 i, err = scanTagsKey(buf, i) 647 state = tagValueState // tag value always follows a tag key 648 case tagValueState: 649 state, i, err = scanTagsValue(buf, i) 650 case fieldsState: 651 indices[commas] = i + 1 652 return i, commas, indices, nil 653 } 654 655 if err != nil { 656 return i, commas, indices, err 657 } 658 } 659} 660 661// scanTagsKey scans each character in a tag key. 662func scanTagsKey(buf []byte, i int) (int, error) { 663 // First character of the key. 664 if i >= len(buf) || buf[i] == ' ' || buf[i] == ',' || buf[i] == '=' { 665 // cpu,{'', ' ', ',', '='} 666 return i, fmt.Errorf("missing tag key") 667 } 668 669 // Examine each character in the tag key until we hit an unescaped 670 // equals (the tag value), or we hit an error (i.e., unescaped 671 // space or comma). 672 for { 673 i++ 674 675 // Either we reached the end of the buffer or we hit an 676 // unescaped comma or space. 677 if i >= len(buf) || 678 ((buf[i] == ' ' || buf[i] == ',') && buf[i-1] != '\\') { 679 // cpu,tag{'', ' ', ','} 680 return i, fmt.Errorf("missing tag value") 681 } 682 683 if buf[i] == '=' && buf[i-1] != '\\' { 684 // cpu,tag= 685 return i + 1, nil 686 } 687 } 688} 689 690// scanTagsValue scans each character in a tag value. 691func scanTagsValue(buf []byte, i int) (int, int, error) { 692 // Tag value cannot be empty. 693 if i >= len(buf) || buf[i] == ',' || buf[i] == ' ' { 694 // cpu,tag={',', ' '} 695 return -1, i, fmt.Errorf("missing tag value") 696 } 697 698 // Examine each character in the tag value until we hit an unescaped 699 // comma (move onto next tag key), an unescaped space (move onto 700 // fields), or we error out. 701 for { 702 i++ 703 if i >= len(buf) { 704 // cpu,tag=value 705 return -1, i, fmt.Errorf("missing fields") 706 } 707 708 // An unescaped equals sign is an invalid tag value. 709 if buf[i] == '=' && buf[i-1] != '\\' { 710 // cpu,tag={'=', 'fo=o'} 711 return -1, i, fmt.Errorf("invalid tag format") 712 } 713 714 if buf[i] == ',' && buf[i-1] != '\\' { 715 // cpu,tag=foo, 716 return tagKeyState, i + 1, nil 717 } 718 719 // cpu,tag=foo value=1.0 720 // cpu, tag=foo\= value=1.0 721 if buf[i] == ' ' && buf[i-1] != '\\' { 722 return fieldsState, i, nil 723 } 724 } 725} 726 727func insertionSort(l, r int, buf []byte, indices []int) { 728 for i := l + 1; i < r; i++ { 729 for j := i; j > l && less(buf, indices, j, j-1); j-- { 730 indices[j], indices[j-1] = indices[j-1], indices[j] 731 } 732 } 733} 734 735func less(buf []byte, indices []int, i, j int) bool { 736 // This grabs the tag names for i & j, it ignores the values 737 _, a := scanTo(buf, indices[i], '=') 738 _, b := scanTo(buf, indices[j], '=') 739 return bytes.Compare(a, b) < 0 740} 741 742// scanFields scans buf, starting at i for the fields section of a point. It returns 743// the ending position and the byte slice of the fields within buf. 744func scanFields(buf []byte, i int) (int, []byte, error) { 745 start := skipWhitespace(buf, i) 746 i = start 747 quoted := false 748 749 // tracks how many '=' we've seen 750 equals := 0 751 752 // tracks how many commas we've seen 753 commas := 0 754 755 for { 756 // reached the end of buf? 757 if i >= len(buf) { 758 break 759 } 760 761 // escaped characters? 762 if buf[i] == '\\' && i+1 < len(buf) { 763 i += 2 764 continue 765 } 766 767 // If the value is quoted, scan until we get to the end quote 768 // Only quote values in the field value since quotes are not significant 769 // in the field key 770 if buf[i] == '"' && equals > commas { 771 quoted = !quoted 772 i++ 773 continue 774 } 775 776 // If we see an =, ensure that there is at least on char before and after it 777 if buf[i] == '=' && !quoted { 778 equals++ 779 780 // check for "... =123" but allow "a\ =123" 781 if buf[i-1] == ' ' && buf[i-2] != '\\' { 782 return i, buf[start:i], fmt.Errorf("missing field key") 783 } 784 785 // check for "...a=123,=456" but allow "a=123,a\,=456" 786 if buf[i-1] == ',' && buf[i-2] != '\\' { 787 return i, buf[start:i], fmt.Errorf("missing field key") 788 } 789 790 // check for "... value=" 791 if i+1 >= len(buf) { 792 return i, buf[start:i], fmt.Errorf("missing field value") 793 } 794 795 // check for "... value=,value2=..." 796 if buf[i+1] == ',' || buf[i+1] == ' ' { 797 return i, buf[start:i], fmt.Errorf("missing field value") 798 } 799 800 if isNumeric(buf[i+1]) || buf[i+1] == '-' || buf[i+1] == 'N' || buf[i+1] == 'n' { 801 var err error 802 i, err = scanNumber(buf, i+1) 803 if err != nil { 804 return i, buf[start:i], err 805 } 806 continue 807 } 808 // If next byte is not a double-quote, the value must be a boolean 809 if buf[i+1] != '"' { 810 var err error 811 i, _, err = scanBoolean(buf, i+1) 812 if err != nil { 813 return i, buf[start:i], err 814 } 815 continue 816 } 817 } 818 819 if buf[i] == ',' && !quoted { 820 commas++ 821 } 822 823 // reached end of block? 824 if buf[i] == ' ' && !quoted { 825 break 826 } 827 i++ 828 } 829 830 if quoted { 831 return i, buf[start:i], fmt.Errorf("unbalanced quotes") 832 } 833 834 // check that all field sections had key and values (e.g. prevent "a=1,b" 835 if equals == 0 || commas != equals-1 { 836 return i, buf[start:i], fmt.Errorf("invalid field format") 837 } 838 839 return i, buf[start:i], nil 840} 841 842// scanTime scans buf, starting at i for the time section of a point. It 843// returns the ending position and the byte slice of the timestamp within buf 844// and and error if the timestamp is not in the correct numeric format. 845func scanTime(buf []byte, i int) (int, []byte, error) { 846 start := skipWhitespace(buf, i) 847 i = start 848 849 for { 850 // reached the end of buf? 851 if i >= len(buf) { 852 break 853 } 854 855 // Reached end of block or trailing whitespace? 856 if buf[i] == '\n' || buf[i] == ' ' { 857 break 858 } 859 860 // Handle negative timestamps 861 if i == start && buf[i] == '-' { 862 i++ 863 continue 864 } 865 866 // Timestamps should be integers, make sure they are so we don't need 867 // to actually parse the timestamp until needed. 868 if buf[i] < '0' || buf[i] > '9' { 869 return i, buf[start:i], fmt.Errorf("bad timestamp") 870 } 871 i++ 872 } 873 return i, buf[start:i], nil 874} 875 876func isNumeric(b byte) bool { 877 return (b >= '0' && b <= '9') || b == '.' 878} 879 880// scanNumber returns the end position within buf, start at i after 881// scanning over buf for an integer, or float. It returns an 882// error if a invalid number is scanned. 883func scanNumber(buf []byte, i int) (int, error) { 884 start := i 885 var isInt, isUnsigned bool 886 887 // Is negative number? 888 if i < len(buf) && buf[i] == '-' { 889 i++ 890 // There must be more characters now, as just '-' is illegal. 891 if i == len(buf) { 892 return i, ErrInvalidNumber 893 } 894 } 895 896 // how many decimal points we've see 897 decimal := false 898 899 // indicates the number is float in scientific notation 900 scientific := false 901 902 for { 903 if i >= len(buf) { 904 break 905 } 906 907 if buf[i] == ',' || buf[i] == ' ' { 908 break 909 } 910 911 if buf[i] == 'i' && i > start && !(isInt || isUnsigned) { 912 isInt = true 913 i++ 914 continue 915 } else if buf[i] == 'u' && i > start && !(isInt || isUnsigned) { 916 isUnsigned = true 917 i++ 918 continue 919 } 920 921 if buf[i] == '.' { 922 // Can't have more than 1 decimal (e.g. 1.1.1 should fail) 923 if decimal { 924 return i, ErrInvalidNumber 925 } 926 decimal = true 927 } 928 929 // `e` is valid for floats but not as the first char 930 if i > start && (buf[i] == 'e' || buf[i] == 'E') { 931 scientific = true 932 i++ 933 continue 934 } 935 936 // + and - are only valid at this point if they follow an e (scientific notation) 937 if (buf[i] == '+' || buf[i] == '-') && (buf[i-1] == 'e' || buf[i-1] == 'E') { 938 i++ 939 continue 940 } 941 942 // NaN is an unsupported value 943 if i+2 < len(buf) && (buf[i] == 'N' || buf[i] == 'n') { 944 return i, ErrInvalidNumber 945 } 946 947 if !isNumeric(buf[i]) { 948 return i, ErrInvalidNumber 949 } 950 i++ 951 } 952 953 if (isInt || isUnsigned) && (decimal || scientific) { 954 return i, ErrInvalidNumber 955 } 956 957 numericDigits := i - start 958 if isInt { 959 numericDigits-- 960 } 961 if decimal { 962 numericDigits-- 963 } 964 if buf[start] == '-' { 965 numericDigits-- 966 } 967 968 if numericDigits == 0 { 969 return i, ErrInvalidNumber 970 } 971 972 // It's more common that numbers will be within min/max range for their type but we need to prevent 973 // out or range numbers from being parsed successfully. This uses some simple heuristics to decide 974 // if we should parse the number to the actual type. It does not do it all the time because it incurs 975 // extra allocations and we end up converting the type again when writing points to disk. 976 if isInt { 977 // Make sure the last char is an 'i' for integers (e.g. 9i10 is not valid) 978 if buf[i-1] != 'i' { 979 return i, ErrInvalidNumber 980 } 981 // Parse the int to check bounds the number of digits could be larger than the max range 982 // We subtract 1 from the index to remove the `i` from our tests 983 if len(buf[start:i-1]) >= maxInt64Digits || len(buf[start:i-1]) >= minInt64Digits { 984 if _, err := parseIntBytes(buf[start:i-1], 10, 64); err != nil { 985 return i, fmt.Errorf("unable to parse integer %s: %s", buf[start:i-1], err) 986 } 987 } 988 } else if isUnsigned { 989 // Return an error if uint64 support has not been enabled. 990 if !enableUint64Support { 991 return i, ErrInvalidNumber 992 } 993 // Make sure the last char is a 'u' for unsigned 994 if buf[i-1] != 'u' { 995 return i, ErrInvalidNumber 996 } 997 // Make sure the first char is not a '-' for unsigned 998 if buf[start] == '-' { 999 return i, ErrInvalidNumber 1000 } 1001 // Parse the uint to check bounds the number of digits could be larger than the max range 1002 // We subtract 1 from the index to remove the `u` from our tests 1003 if len(buf[start:i-1]) >= maxUint64Digits { 1004 if _, err := parseUintBytes(buf[start:i-1], 10, 64); err != nil { 1005 return i, fmt.Errorf("unable to parse unsigned %s: %s", buf[start:i-1], err) 1006 } 1007 } 1008 } else { 1009 // Parse the float to check bounds if it's scientific or the number of digits could be larger than the max range 1010 if scientific || len(buf[start:i]) >= maxFloat64Digits || len(buf[start:i]) >= minFloat64Digits { 1011 if _, err := parseFloatBytes(buf[start:i], 10); err != nil { 1012 return i, fmt.Errorf("invalid float") 1013 } 1014 } 1015 } 1016 1017 return i, nil 1018} 1019 1020// scanBoolean returns the end position within buf, start at i after 1021// scanning over buf for boolean. Valid values for a boolean are 1022// t, T, true, TRUE, f, F, false, FALSE. It returns an error if a invalid boolean 1023// is scanned. 1024func scanBoolean(buf []byte, i int) (int, []byte, error) { 1025 start := i 1026 1027 if i < len(buf) && (buf[i] != 't' && buf[i] != 'f' && buf[i] != 'T' && buf[i] != 'F') { 1028 return i, buf[start:i], fmt.Errorf("invalid boolean") 1029 } 1030 1031 i++ 1032 for { 1033 if i >= len(buf) { 1034 break 1035 } 1036 1037 if buf[i] == ',' || buf[i] == ' ' { 1038 break 1039 } 1040 i++ 1041 } 1042 1043 // Single char bool (t, T, f, F) is ok 1044 if i-start == 1 { 1045 return i, buf[start:i], nil 1046 } 1047 1048 // length must be 4 for true or TRUE 1049 if (buf[start] == 't' || buf[start] == 'T') && i-start != 4 { 1050 return i, buf[start:i], fmt.Errorf("invalid boolean") 1051 } 1052 1053 // length must be 5 for false or FALSE 1054 if (buf[start] == 'f' || buf[start] == 'F') && i-start != 5 { 1055 return i, buf[start:i], fmt.Errorf("invalid boolean") 1056 } 1057 1058 // Otherwise 1059 valid := false 1060 switch buf[start] { 1061 case 't': 1062 valid = bytes.Equal(buf[start:i], []byte("true")) 1063 case 'f': 1064 valid = bytes.Equal(buf[start:i], []byte("false")) 1065 case 'T': 1066 valid = bytes.Equal(buf[start:i], []byte("TRUE")) || bytes.Equal(buf[start:i], []byte("True")) 1067 case 'F': 1068 valid = bytes.Equal(buf[start:i], []byte("FALSE")) || bytes.Equal(buf[start:i], []byte("False")) 1069 } 1070 1071 if !valid { 1072 return i, buf[start:i], fmt.Errorf("invalid boolean") 1073 } 1074 1075 return i, buf[start:i], nil 1076 1077} 1078 1079// skipWhitespace returns the end position within buf, starting at i after 1080// scanning over spaces in tags. 1081func skipWhitespace(buf []byte, i int) int { 1082 for i < len(buf) { 1083 if buf[i] != ' ' && buf[i] != '\t' && buf[i] != 0 { 1084 break 1085 } 1086 i++ 1087 } 1088 return i 1089} 1090 1091// scanLine returns the end position in buf and the next line found within 1092// buf. 1093func scanLine(buf []byte, i int) (int, []byte) { 1094 start := i 1095 quoted := false 1096 fields := false 1097 1098 // tracks how many '=' and commas we've seen 1099 // this duplicates some of the functionality in scanFields 1100 equals := 0 1101 commas := 0 1102 for { 1103 // reached the end of buf? 1104 if i >= len(buf) { 1105 break 1106 } 1107 1108 // skip past escaped characters 1109 if buf[i] == '\\' && i+2 < len(buf) { 1110 i += 2 1111 continue 1112 } 1113 1114 if buf[i] == ' ' { 1115 fields = true 1116 } 1117 1118 // If we see a double quote, makes sure it is not escaped 1119 if fields { 1120 if !quoted && buf[i] == '=' { 1121 i++ 1122 equals++ 1123 continue 1124 } else if !quoted && buf[i] == ',' { 1125 i++ 1126 commas++ 1127 continue 1128 } else if buf[i] == '"' && equals > commas { 1129 i++ 1130 quoted = !quoted 1131 continue 1132 } 1133 } 1134 1135 if buf[i] == '\n' && !quoted { 1136 break 1137 } 1138 1139 i++ 1140 } 1141 1142 return i, buf[start:i] 1143} 1144 1145// scanTo returns the end position in buf and the next consecutive block 1146// of bytes, starting from i and ending with stop byte, where stop byte 1147// has not been escaped. 1148// 1149// If there are leading spaces, they are skipped. 1150func scanTo(buf []byte, i int, stop byte) (int, []byte) { 1151 start := i 1152 for { 1153 // reached the end of buf? 1154 if i >= len(buf) { 1155 break 1156 } 1157 1158 // Reached unescaped stop value? 1159 if buf[i] == stop && (i == 0 || buf[i-1] != '\\') { 1160 break 1161 } 1162 i++ 1163 } 1164 1165 return i, buf[start:i] 1166} 1167 1168// scanTo returns the end position in buf and the next consecutive block 1169// of bytes, starting from i and ending with stop byte. If there are leading 1170// spaces, they are skipped. 1171func scanToSpaceOr(buf []byte, i int, stop byte) (int, []byte) { 1172 start := i 1173 if buf[i] == stop || buf[i] == ' ' { 1174 return i, buf[start:i] 1175 } 1176 1177 for { 1178 i++ 1179 if buf[i-1] == '\\' { 1180 continue 1181 } 1182 1183 // reached the end of buf? 1184 if i >= len(buf) { 1185 return i, buf[start:i] 1186 } 1187 1188 // reached end of block? 1189 if buf[i] == stop || buf[i] == ' ' { 1190 return i, buf[start:i] 1191 } 1192 } 1193} 1194 1195func scanTagValue(buf []byte, i int) (int, []byte) { 1196 start := i 1197 for { 1198 if i >= len(buf) { 1199 break 1200 } 1201 1202 if buf[i] == ',' && buf[i-1] != '\\' { 1203 break 1204 } 1205 i++ 1206 } 1207 if i > len(buf) { 1208 return i, nil 1209 } 1210 return i, buf[start:i] 1211} 1212 1213func scanFieldValue(buf []byte, i int) (int, []byte) { 1214 start := i 1215 quoted := false 1216 for i < len(buf) { 1217 // Only escape char for a field value is a double-quote and backslash 1218 if buf[i] == '\\' && i+1 < len(buf) && (buf[i+1] == '"' || buf[i+1] == '\\') { 1219 i += 2 1220 continue 1221 } 1222 1223 // Quoted value? (e.g. string) 1224 if buf[i] == '"' { 1225 i++ 1226 quoted = !quoted 1227 continue 1228 } 1229 1230 if buf[i] == ',' && !quoted { 1231 break 1232 } 1233 i++ 1234 } 1235 return i, buf[start:i] 1236} 1237 1238func EscapeMeasurement(in []byte) []byte { 1239 for _, c := range measurementEscapeCodes { 1240 if bytes.IndexByte(in, c.k[0]) != -1 { 1241 in = bytes.Replace(in, c.k[:], c.esc[:], -1) 1242 } 1243 } 1244 return in 1245} 1246 1247func unescapeMeasurement(in []byte) []byte { 1248 if bytes.IndexByte(in, '\\') == -1 { 1249 return in 1250 } 1251 1252 for i := range measurementEscapeCodes { 1253 c := &measurementEscapeCodes[i] 1254 if bytes.IndexByte(in, c.k[0]) != -1 { 1255 in = bytes.Replace(in, c.esc[:], c.k[:], -1) 1256 } 1257 } 1258 return in 1259} 1260 1261func escapeTag(in []byte) []byte { 1262 for i := range tagEscapeCodes { 1263 c := &tagEscapeCodes[i] 1264 if bytes.IndexByte(in, c.k[0]) != -1 { 1265 in = bytes.Replace(in, c.k[:], c.esc[:], -1) 1266 } 1267 } 1268 return in 1269} 1270 1271func unescapeTag(in []byte) []byte { 1272 if bytes.IndexByte(in, '\\') == -1 { 1273 return in 1274 } 1275 1276 for i := range tagEscapeCodes { 1277 c := &tagEscapeCodes[i] 1278 if bytes.IndexByte(in, c.k[0]) != -1 { 1279 in = bytes.Replace(in, c.esc[:], c.k[:], -1) 1280 } 1281 } 1282 return in 1283} 1284 1285// escapeStringFieldReplacer replaces double quotes and backslashes 1286// with the same character preceded by a backslash. 1287// As of Go 1.7 this benchmarked better in allocations and CPU time 1288// compared to iterating through a string byte-by-byte and appending to a new byte slice, 1289// calling strings.Replace twice, and better than (*Regex).ReplaceAllString. 1290var escapeStringFieldReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`) 1291 1292// EscapeStringField returns a copy of in with any double quotes or 1293// backslashes with escaped values. 1294func EscapeStringField(in string) string { 1295 return escapeStringFieldReplacer.Replace(in) 1296} 1297 1298// unescapeStringField returns a copy of in with any escaped double-quotes 1299// or backslashes unescaped. 1300func unescapeStringField(in string) string { 1301 if strings.IndexByte(in, '\\') == -1 { 1302 return in 1303 } 1304 1305 var out []byte 1306 i := 0 1307 for { 1308 if i >= len(in) { 1309 break 1310 } 1311 // unescape backslashes 1312 if in[i] == '\\' && i+1 < len(in) && in[i+1] == '\\' { 1313 out = append(out, '\\') 1314 i += 2 1315 continue 1316 } 1317 // unescape double-quotes 1318 if in[i] == '\\' && i+1 < len(in) && in[i+1] == '"' { 1319 out = append(out, '"') 1320 i += 2 1321 continue 1322 } 1323 out = append(out, in[i]) 1324 i++ 1325 1326 } 1327 return string(out) 1328} 1329 1330// NewPoint returns a new point with the given measurement name, tags, fields and timestamp. If 1331// an unsupported field value (NaN, or +/-Inf) or out of range time is passed, this function 1332// returns an error. 1333func NewPoint(name string, tags Tags, fields Fields, t time.Time) (Point, error) { 1334 key, err := pointKey(name, tags, fields, t) 1335 if err != nil { 1336 return nil, err 1337 } 1338 1339 return &point{ 1340 key: key, 1341 time: t, 1342 fields: fields.MarshalBinary(), 1343 }, nil 1344} 1345 1346// pointKey checks some basic requirements for valid points, and returns the 1347// key, along with an possible error. 1348func pointKey(measurement string, tags Tags, fields Fields, t time.Time) ([]byte, error) { 1349 if len(fields) == 0 { 1350 return nil, ErrPointMustHaveAField 1351 } 1352 1353 if !t.IsZero() { 1354 if err := CheckTime(t); err != nil { 1355 return nil, err 1356 } 1357 } 1358 1359 for key, value := range fields { 1360 switch value := value.(type) { 1361 case float64: 1362 // Ensure the caller validates and handles invalid field values 1363 if math.IsInf(value, 0) { 1364 return nil, fmt.Errorf("+/-Inf is an unsupported value for field %s", key) 1365 } 1366 if math.IsNaN(value) { 1367 return nil, fmt.Errorf("NaN is an unsupported value for field %s", key) 1368 } 1369 case float32: 1370 // Ensure the caller validates and handles invalid field values 1371 if math.IsInf(float64(value), 0) { 1372 return nil, fmt.Errorf("+/-Inf is an unsupported value for field %s", key) 1373 } 1374 if math.IsNaN(float64(value)) { 1375 return nil, fmt.Errorf("NaN is an unsupported value for field %s", key) 1376 } 1377 } 1378 if len(key) == 0 { 1379 return nil, fmt.Errorf("all fields must have non-empty names") 1380 } 1381 } 1382 1383 key := MakeKey([]byte(measurement), tags) 1384 for field := range fields { 1385 sz := seriesKeySize(key, []byte(field)) 1386 if sz > MaxKeyLength { 1387 return nil, fmt.Errorf("max key length exceeded: %v > %v", sz, MaxKeyLength) 1388 } 1389 } 1390 1391 return key, nil 1392} 1393 1394func seriesKeySize(key, field []byte) int { 1395 // 4 is the length of the tsm1.fieldKeySeparator constant. It's inlined here to avoid a circular 1396 // dependency. 1397 return len(key) + 4 + len(field) 1398} 1399 1400// NewPointFromBytes returns a new Point from a marshalled Point. 1401func NewPointFromBytes(b []byte) (Point, error) { 1402 p := &point{} 1403 if err := p.UnmarshalBinary(b); err != nil { 1404 return nil, err 1405 } 1406 1407 // This does some basic validation to ensure there are fields and they 1408 // can be unmarshalled as well. 1409 iter := p.FieldIterator() 1410 var hasField bool 1411 for iter.Next() { 1412 if len(iter.FieldKey()) == 0 { 1413 continue 1414 } 1415 hasField = true 1416 switch iter.Type() { 1417 case Float: 1418 _, err := iter.FloatValue() 1419 if err != nil { 1420 return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) 1421 } 1422 case Integer: 1423 _, err := iter.IntegerValue() 1424 if err != nil { 1425 return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) 1426 } 1427 case Unsigned: 1428 _, err := iter.UnsignedValue() 1429 if err != nil { 1430 return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) 1431 } 1432 case String: 1433 // Skip since this won't return an error 1434 case Boolean: 1435 _, err := iter.BooleanValue() 1436 if err != nil { 1437 return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) 1438 } 1439 } 1440 } 1441 1442 if !hasField { 1443 return nil, ErrPointMustHaveAField 1444 } 1445 1446 return p, nil 1447} 1448 1449// MustNewPoint returns a new point with the given measurement name, tags, fields and timestamp. If 1450// an unsupported field value (NaN) is passed, this function panics. 1451func MustNewPoint(name string, tags Tags, fields Fields, time time.Time) Point { 1452 pt, err := NewPoint(name, tags, fields, time) 1453 if err != nil { 1454 panic(err.Error()) 1455 } 1456 return pt 1457} 1458 1459// Key returns the key (measurement joined with tags) of the point. 1460func (p *point) Key() []byte { 1461 return p.key 1462} 1463 1464func (p *point) name() []byte { 1465 _, name := scanTo(p.key, 0, ',') 1466 return name 1467} 1468 1469func (p *point) Name() []byte { 1470 return escape.Unescape(p.name()) 1471} 1472 1473// SetName updates the measurement name for the point. 1474func (p *point) SetName(name string) { 1475 p.cachedName = "" 1476 p.key = MakeKey([]byte(name), p.Tags()) 1477} 1478 1479// Time return the timestamp for the point. 1480func (p *point) Time() time.Time { 1481 return p.time 1482} 1483 1484// SetTime updates the timestamp for the point. 1485func (p *point) SetTime(t time.Time) { 1486 p.time = t 1487} 1488 1489// Round will round the timestamp of the point to the given duration. 1490func (p *point) Round(d time.Duration) { 1491 p.time = p.time.Round(d) 1492} 1493 1494// Tags returns the tag set for the point. 1495func (p *point) Tags() Tags { 1496 if p.cachedTags != nil { 1497 return p.cachedTags 1498 } 1499 p.cachedTags = parseTags(p.key, nil) 1500 return p.cachedTags 1501} 1502 1503func (p *point) ForEachTag(fn func(k, v []byte) bool) { 1504 walkTags(p.key, fn) 1505} 1506 1507func (p *point) HasTag(tag []byte) bool { 1508 if len(p.key) == 0 { 1509 return false 1510 } 1511 1512 var exists bool 1513 walkTags(p.key, func(key, value []byte) bool { 1514 if bytes.Equal(tag, key) { 1515 exists = true 1516 return false 1517 } 1518 return true 1519 }) 1520 1521 return exists 1522} 1523 1524func walkTags(buf []byte, fn func(key, value []byte) bool) { 1525 if len(buf) == 0 { 1526 return 1527 } 1528 1529 pos, name := scanTo(buf, 0, ',') 1530 1531 // it's an empty key, so there are no tags 1532 if len(name) == 0 { 1533 return 1534 } 1535 1536 hasEscape := bytes.IndexByte(buf, '\\') != -1 1537 i := pos + 1 1538 var key, value []byte 1539 for { 1540 if i >= len(buf) { 1541 break 1542 } 1543 i, key = scanTo(buf, i, '=') 1544 i, value = scanTagValue(buf, i+1) 1545 1546 if len(value) == 0 { 1547 continue 1548 } 1549 1550 if hasEscape { 1551 if !fn(unescapeTag(key), unescapeTag(value)) { 1552 return 1553 } 1554 } else { 1555 if !fn(key, value) { 1556 return 1557 } 1558 } 1559 1560 i++ 1561 } 1562} 1563 1564// walkFields walks each field key and value via fn. If fn returns false, the iteration 1565// is stopped. The values are the raw byte slices and not the converted types. 1566func walkFields(buf []byte, fn func(key, value []byte) bool) error { 1567 var i int 1568 var key, val []byte 1569 for len(buf) > 0 { 1570 i, key = scanTo(buf, 0, '=') 1571 if i > len(buf)-2 { 1572 return fmt.Errorf("invalid value: field-key=%s", key) 1573 } 1574 buf = buf[i+1:] 1575 i, val = scanFieldValue(buf, 0) 1576 buf = buf[i:] 1577 if !fn(key, val) { 1578 break 1579 } 1580 1581 // slice off comma 1582 if len(buf) > 0 { 1583 buf = buf[1:] 1584 } 1585 } 1586 return nil 1587} 1588 1589// parseTags parses buf into the provided destination tags, returning destination 1590// Tags, which may have a different length and capacity. 1591func parseTags(buf []byte, dst Tags) Tags { 1592 if len(buf) == 0 { 1593 return nil 1594 } 1595 1596 n := bytes.Count(buf, []byte(",")) 1597 if cap(dst) < n { 1598 dst = make(Tags, n) 1599 } else { 1600 dst = dst[:n] 1601 } 1602 1603 // Ensure existing behaviour when point has no tags and nil slice passed in. 1604 if dst == nil { 1605 dst = Tags{} 1606 } 1607 1608 // Series keys can contain escaped commas, therefore the number of commas 1609 // in a series key only gives an estimation of the upper bound on the number 1610 // of tags. 1611 var i int 1612 walkTags(buf, func(key, value []byte) bool { 1613 dst[i].Key, dst[i].Value = key, value 1614 i++ 1615 return true 1616 }) 1617 return dst[:i] 1618} 1619 1620// MakeKey creates a key for a set of tags. 1621func MakeKey(name []byte, tags Tags) []byte { 1622 return AppendMakeKey(nil, name, tags) 1623} 1624 1625// AppendMakeKey appends the key derived from name and tags to dst and returns the extended buffer. 1626func AppendMakeKey(dst []byte, name []byte, tags Tags) []byte { 1627 // unescape the name and then re-escape it to avoid double escaping. 1628 // The key should always be stored in escaped form. 1629 dst = append(dst, EscapeMeasurement(unescapeMeasurement(name))...) 1630 dst = tags.AppendHashKey(dst) 1631 return dst 1632} 1633 1634// SetTags replaces the tags for the point. 1635func (p *point) SetTags(tags Tags) { 1636 p.key = MakeKey(p.Name(), tags) 1637 p.cachedTags = tags 1638} 1639 1640// AddTag adds or replaces a tag value for a point. 1641func (p *point) AddTag(key, value string) { 1642 tags := p.Tags() 1643 tags = append(tags, Tag{Key: []byte(key), Value: []byte(value)}) 1644 sort.Sort(tags) 1645 p.cachedTags = tags 1646 p.key = MakeKey(p.Name(), tags) 1647} 1648 1649// Fields returns the fields for the point. 1650func (p *point) Fields() (Fields, error) { 1651 if p.cachedFields != nil { 1652 return p.cachedFields, nil 1653 } 1654 cf, err := p.unmarshalBinary() 1655 if err != nil { 1656 return nil, err 1657 } 1658 p.cachedFields = cf 1659 return p.cachedFields, nil 1660} 1661 1662// SetPrecision will round a time to the specified precision. 1663func (p *point) SetPrecision(precision string) { 1664 switch precision { 1665 case "n": 1666 case "u": 1667 p.SetTime(p.Time().Truncate(time.Microsecond)) 1668 case "ms": 1669 p.SetTime(p.Time().Truncate(time.Millisecond)) 1670 case "s": 1671 p.SetTime(p.Time().Truncate(time.Second)) 1672 case "m": 1673 p.SetTime(p.Time().Truncate(time.Minute)) 1674 case "h": 1675 p.SetTime(p.Time().Truncate(time.Hour)) 1676 } 1677} 1678 1679// String returns the string representation of the point. 1680func (p *point) String() string { 1681 if p.Time().IsZero() { 1682 return string(p.Key()) + " " + string(p.fields) 1683 } 1684 return string(p.Key()) + " " + string(p.fields) + " " + strconv.FormatInt(p.UnixNano(), 10) 1685} 1686 1687// AppendString appends the string representation of the point to buf. 1688func (p *point) AppendString(buf []byte) []byte { 1689 buf = append(buf, p.key...) 1690 buf = append(buf, ' ') 1691 buf = append(buf, p.fields...) 1692 1693 if !p.time.IsZero() { 1694 buf = append(buf, ' ') 1695 buf = strconv.AppendInt(buf, p.UnixNano(), 10) 1696 } 1697 1698 return buf 1699} 1700 1701// StringSize returns the length of the string that would be returned by String(). 1702func (p *point) StringSize() int { 1703 size := len(p.key) + len(p.fields) + 1 1704 1705 if !p.time.IsZero() { 1706 digits := 1 // even "0" has one digit 1707 t := p.UnixNano() 1708 if t < 0 { 1709 // account for negative sign, then negate 1710 digits++ 1711 t = -t 1712 } 1713 for t > 9 { // already accounted for one digit 1714 digits++ 1715 t /= 10 1716 } 1717 size += digits + 1 // digits and a space 1718 } 1719 1720 return size 1721} 1722 1723// MarshalBinary returns a binary representation of the point. 1724func (p *point) MarshalBinary() ([]byte, error) { 1725 if len(p.fields) == 0 { 1726 return nil, ErrPointMustHaveAField 1727 } 1728 1729 tb, err := p.time.MarshalBinary() 1730 if err != nil { 1731 return nil, err 1732 } 1733 1734 b := make([]byte, 8+len(p.key)+len(p.fields)+len(tb)) 1735 i := 0 1736 1737 binary.BigEndian.PutUint32(b[i:], uint32(len(p.key))) 1738 i += 4 1739 1740 i += copy(b[i:], p.key) 1741 1742 binary.BigEndian.PutUint32(b[i:i+4], uint32(len(p.fields))) 1743 i += 4 1744 1745 i += copy(b[i:], p.fields) 1746 1747 copy(b[i:], tb) 1748 return b, nil 1749} 1750 1751// UnmarshalBinary decodes a binary representation of the point into a point struct. 1752func (p *point) UnmarshalBinary(b []byte) error { 1753 var n int 1754 1755 // Read key length. 1756 if len(b) < 4 { 1757 return io.ErrShortBuffer 1758 } 1759 n, b = int(binary.BigEndian.Uint32(b[:4])), b[4:] 1760 1761 // Read key. 1762 if len(b) < n { 1763 return io.ErrShortBuffer 1764 } 1765 p.key, b = b[:n], b[n:] 1766 1767 // Read fields length. 1768 if len(b) < 4 { 1769 return io.ErrShortBuffer 1770 } 1771 n, b = int(binary.BigEndian.Uint32(b[:4])), b[4:] 1772 1773 // Read fields. 1774 if len(b) < n { 1775 return io.ErrShortBuffer 1776 } 1777 p.fields, b = b[:n], b[n:] 1778 1779 // Read timestamp. 1780 return p.time.UnmarshalBinary(b) 1781} 1782 1783// PrecisionString returns a string representation of the point. If there 1784// is a timestamp associated with the point then it will be specified in the 1785// given unit. 1786func (p *point) PrecisionString(precision string) string { 1787 if p.Time().IsZero() { 1788 return fmt.Sprintf("%s %s", p.Key(), string(p.fields)) 1789 } 1790 return fmt.Sprintf("%s %s %d", p.Key(), string(p.fields), 1791 p.UnixNano()/GetPrecisionMultiplier(precision)) 1792} 1793 1794// RoundedString returns a string representation of the point. If there 1795// is a timestamp associated with the point, then it will be rounded to the 1796// given duration. 1797func (p *point) RoundedString(d time.Duration) string { 1798 if p.Time().IsZero() { 1799 return fmt.Sprintf("%s %s", p.Key(), string(p.fields)) 1800 } 1801 return fmt.Sprintf("%s %s %d", p.Key(), string(p.fields), 1802 p.time.Round(d).UnixNano()) 1803} 1804 1805func (p *point) unmarshalBinary() (Fields, error) { 1806 iter := p.FieldIterator() 1807 fields := make(Fields, 8) 1808 for iter.Next() { 1809 if len(iter.FieldKey()) == 0 { 1810 continue 1811 } 1812 switch iter.Type() { 1813 case Float: 1814 v, err := iter.FloatValue() 1815 if err != nil { 1816 return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) 1817 } 1818 fields[string(iter.FieldKey())] = v 1819 case Integer: 1820 v, err := iter.IntegerValue() 1821 if err != nil { 1822 return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) 1823 } 1824 fields[string(iter.FieldKey())] = v 1825 case Unsigned: 1826 v, err := iter.UnsignedValue() 1827 if err != nil { 1828 return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) 1829 } 1830 fields[string(iter.FieldKey())] = v 1831 case String: 1832 fields[string(iter.FieldKey())] = iter.StringValue() 1833 case Boolean: 1834 v, err := iter.BooleanValue() 1835 if err != nil { 1836 return nil, fmt.Errorf("unable to unmarshal field %s: %s", string(iter.FieldKey()), err) 1837 } 1838 fields[string(iter.FieldKey())] = v 1839 } 1840 } 1841 return fields, nil 1842} 1843 1844// HashID returns a non-cryptographic checksum of the point's key. 1845func (p *point) HashID() uint64 { 1846 h := NewInlineFNV64a() 1847 h.Write(p.key) 1848 sum := h.Sum64() 1849 return sum 1850} 1851 1852// UnixNano returns the timestamp of the point as nanoseconds since Unix epoch. 1853func (p *point) UnixNano() int64 { 1854 return p.Time().UnixNano() 1855} 1856 1857// Split will attempt to return multiple points with the same timestamp whose 1858// string representations are no longer than size. Points with a single field or 1859// a point without a timestamp may exceed the requested size. 1860func (p *point) Split(size int) []Point { 1861 if p.time.IsZero() || p.StringSize() <= size { 1862 return []Point{p} 1863 } 1864 1865 // key string, timestamp string, spaces 1866 size -= len(p.key) + len(strconv.FormatInt(p.time.UnixNano(), 10)) + 2 1867 1868 var points []Point 1869 var start, cur int 1870 1871 for cur < len(p.fields) { 1872 end, _ := scanTo(p.fields, cur, '=') 1873 end, _ = scanFieldValue(p.fields, end+1) 1874 1875 if cur > start && end-start > size { 1876 points = append(points, &point{ 1877 key: p.key, 1878 time: p.time, 1879 fields: p.fields[start : cur-1], 1880 }) 1881 start = cur 1882 } 1883 1884 cur = end + 1 1885 } 1886 1887 points = append(points, &point{ 1888 key: p.key, 1889 time: p.time, 1890 fields: p.fields[start:], 1891 }) 1892 1893 return points 1894} 1895 1896// Tag represents a single key/value tag pair. 1897type Tag struct { 1898 Key []byte 1899 Value []byte 1900} 1901 1902// NewTag returns a new Tag. 1903func NewTag(key, value []byte) Tag { 1904 return Tag{ 1905 Key: key, 1906 Value: value, 1907 } 1908} 1909 1910// Size returns the size of the key and value. 1911func (t Tag) Size() int { return len(t.Key) + len(t.Value) } 1912 1913// Clone returns a shallow copy of Tag. 1914// 1915// Tags associated with a Point created by ParsePointsWithPrecision will hold references to the byte slice that was parsed. 1916// Use Clone to create a Tag with new byte slices that do not refer to the argument to ParsePointsWithPrecision. 1917func (t Tag) Clone() Tag { 1918 other := Tag{ 1919 Key: make([]byte, len(t.Key)), 1920 Value: make([]byte, len(t.Value)), 1921 } 1922 1923 copy(other.Key, t.Key) 1924 copy(other.Value, t.Value) 1925 1926 return other 1927} 1928 1929// String returns the string reprsentation of the tag. 1930func (t *Tag) String() string { 1931 var buf bytes.Buffer 1932 buf.WriteByte('{') 1933 buf.WriteString(string(t.Key)) 1934 buf.WriteByte(' ') 1935 buf.WriteString(string(t.Value)) 1936 buf.WriteByte('}') 1937 return buf.String() 1938} 1939 1940// Tags represents a sorted list of tags. 1941type Tags []Tag 1942 1943// NewTags returns a new Tags from a map. 1944func NewTags(m map[string]string) Tags { 1945 if len(m) == 0 { 1946 return nil 1947 } 1948 a := make(Tags, 0, len(m)) 1949 for k, v := range m { 1950 a = append(a, NewTag([]byte(k), []byte(v))) 1951 } 1952 sort.Sort(a) 1953 return a 1954} 1955 1956// Keys returns the list of keys for a tag set. 1957func (a Tags) Keys() []string { 1958 if len(a) == 0 { 1959 return nil 1960 } 1961 keys := make([]string, len(a)) 1962 for i, tag := range a { 1963 keys[i] = string(tag.Key) 1964 } 1965 return keys 1966} 1967 1968// Values returns the list of values for a tag set. 1969func (a Tags) Values() []string { 1970 if len(a) == 0 { 1971 return nil 1972 } 1973 values := make([]string, len(a)) 1974 for i, tag := range a { 1975 values[i] = string(tag.Value) 1976 } 1977 return values 1978} 1979 1980// String returns the string representation of the tags. 1981func (a Tags) String() string { 1982 var buf bytes.Buffer 1983 buf.WriteByte('[') 1984 for i := range a { 1985 buf.WriteString(a[i].String()) 1986 if i < len(a)-1 { 1987 buf.WriteByte(' ') 1988 } 1989 } 1990 buf.WriteByte(']') 1991 return buf.String() 1992} 1993 1994// Size returns the number of bytes needed to store all tags. Note, this is 1995// the number of bytes needed to store all keys and values and does not account 1996// for data structures or delimiters for example. 1997func (a Tags) Size() int { 1998 var total int 1999 for i := range a { 2000 total += a[i].Size() 2001 } 2002 return total 2003} 2004 2005// Clone returns a copy of the slice where the elements are a result of calling `Clone` on the original elements 2006// 2007// Tags associated with a Point created by ParsePointsWithPrecision will hold references to the byte slice that was parsed. 2008// Use Clone to create Tags with new byte slices that do not refer to the argument to ParsePointsWithPrecision. 2009func (a Tags) Clone() Tags { 2010 if len(a) == 0 { 2011 return nil 2012 } 2013 2014 others := make(Tags, len(a)) 2015 for i := range a { 2016 others[i] = a[i].Clone() 2017 } 2018 2019 return others 2020} 2021 2022func (a Tags) Len() int { return len(a) } 2023func (a Tags) Less(i, j int) bool { return bytes.Compare(a[i].Key, a[j].Key) == -1 } 2024func (a Tags) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 2025 2026// Equal returns true if a equals other. 2027func (a Tags) Equal(other Tags) bool { 2028 if len(a) != len(other) { 2029 return false 2030 } 2031 for i := range a { 2032 if !bytes.Equal(a[i].Key, other[i].Key) || !bytes.Equal(a[i].Value, other[i].Value) { 2033 return false 2034 } 2035 } 2036 return true 2037} 2038 2039// CompareTags returns -1 if a < b, 1 if a > b, and 0 if a == b. 2040func CompareTags(a, b Tags) int { 2041 // Compare each key & value until a mismatch. 2042 for i := 0; i < len(a) && i < len(b); i++ { 2043 if cmp := bytes.Compare(a[i].Key, b[i].Key); cmp != 0 { 2044 return cmp 2045 } 2046 if cmp := bytes.Compare(a[i].Value, b[i].Value); cmp != 0 { 2047 return cmp 2048 } 2049 } 2050 2051 // If all tags are equal up to this point then return shorter tagset. 2052 if len(a) < len(b) { 2053 return -1 2054 } else if len(a) > len(b) { 2055 return 1 2056 } 2057 2058 // All tags are equal. 2059 return 0 2060} 2061 2062// Get returns the value for a key. 2063func (a Tags) Get(key []byte) []byte { 2064 // OPTIMIZE: Use sort.Search if tagset is large. 2065 2066 for _, t := range a { 2067 if bytes.Equal(t.Key, key) { 2068 return t.Value 2069 } 2070 } 2071 return nil 2072} 2073 2074// GetString returns the string value for a string key. 2075func (a Tags) GetString(key string) string { 2076 return string(a.Get([]byte(key))) 2077} 2078 2079// Set sets the value for a key. 2080func (a *Tags) Set(key, value []byte) { 2081 for i, t := range *a { 2082 if bytes.Equal(t.Key, key) { 2083 (*a)[i].Value = value 2084 return 2085 } 2086 } 2087 *a = append(*a, Tag{Key: key, Value: value}) 2088 sort.Sort(*a) 2089} 2090 2091// SetString sets the string value for a string key. 2092func (a *Tags) SetString(key, value string) { 2093 a.Set([]byte(key), []byte(value)) 2094} 2095 2096// Delete removes a tag by key. 2097func (a *Tags) Delete(key []byte) { 2098 for i, t := range *a { 2099 if bytes.Equal(t.Key, key) { 2100 copy((*a)[i:], (*a)[i+1:]) 2101 (*a)[len(*a)-1] = Tag{} 2102 *a = (*a)[:len(*a)-1] 2103 return 2104 } 2105 } 2106} 2107 2108// Map returns a map representation of the tags. 2109func (a Tags) Map() map[string]string { 2110 m := make(map[string]string, len(a)) 2111 for _, t := range a { 2112 m[string(t.Key)] = string(t.Value) 2113 } 2114 return m 2115} 2116 2117// Merge merges the tags combining the two. If both define a tag with the 2118// same key, the merged value overwrites the old value. 2119// A new map is returned. 2120func (a Tags) Merge(other map[string]string) Tags { 2121 merged := make(map[string]string, len(a)+len(other)) 2122 for _, t := range a { 2123 merged[string(t.Key)] = string(t.Value) 2124 } 2125 for k, v := range other { 2126 merged[k] = v 2127 } 2128 return NewTags(merged) 2129} 2130 2131// HashKey hashes all of a tag's keys. 2132func (a Tags) HashKey() []byte { 2133 return a.AppendHashKey(nil) 2134} 2135 2136func (a Tags) needsEscape() bool { 2137 for i := range a { 2138 t := &a[i] 2139 for j := range tagEscapeCodes { 2140 c := &tagEscapeCodes[j] 2141 if bytes.IndexByte(t.Key, c.k[0]) != -1 || bytes.IndexByte(t.Value, c.k[0]) != -1 { 2142 return true 2143 } 2144 } 2145 } 2146 return false 2147} 2148 2149// AppendHashKey appends the result of hashing all of a tag's keys and values to dst and returns the extended buffer. 2150func (a Tags) AppendHashKey(dst []byte) []byte { 2151 // Empty maps marshal to empty bytes. 2152 if len(a) == 0 { 2153 return dst 2154 } 2155 2156 // Type invariant: Tags are sorted 2157 2158 sz := 0 2159 var escaped Tags 2160 if a.needsEscape() { 2161 var tmp [20]Tag 2162 if len(a) < len(tmp) { 2163 escaped = tmp[:len(a)] 2164 } else { 2165 escaped = make(Tags, len(a)) 2166 } 2167 2168 for i := range a { 2169 t := &a[i] 2170 nt := &escaped[i] 2171 nt.Key = escapeTag(t.Key) 2172 nt.Value = escapeTag(t.Value) 2173 sz += len(nt.Key) + len(nt.Value) 2174 } 2175 } else { 2176 sz = a.Size() 2177 escaped = a 2178 } 2179 2180 sz += len(escaped) + (len(escaped) * 2) // separators 2181 2182 // Generate marshaled bytes. 2183 if cap(dst)-len(dst) < sz { 2184 nd := make([]byte, len(dst), len(dst)+sz) 2185 copy(nd, dst) 2186 dst = nd 2187 } 2188 buf := dst[len(dst) : len(dst)+sz] 2189 idx := 0 2190 for i := range escaped { 2191 k := &escaped[i] 2192 if len(k.Value) == 0 { 2193 continue 2194 } 2195 buf[idx] = ',' 2196 idx++ 2197 copy(buf[idx:], k.Key) 2198 idx += len(k.Key) 2199 buf[idx] = '=' 2200 idx++ 2201 copy(buf[idx:], k.Value) 2202 idx += len(k.Value) 2203 } 2204 return dst[:len(dst)+idx] 2205} 2206 2207// CopyTags returns a shallow copy of tags. 2208func CopyTags(a Tags) Tags { 2209 other := make(Tags, len(a)) 2210 copy(other, a) 2211 return other 2212} 2213 2214// DeepCopyTags returns a deep copy of tags. 2215func DeepCopyTags(a Tags) Tags { 2216 // Calculate size of keys/values in bytes. 2217 var n int 2218 for _, t := range a { 2219 n += len(t.Key) + len(t.Value) 2220 } 2221 2222 // Build single allocation for all key/values. 2223 buf := make([]byte, n) 2224 2225 // Copy tags to new set. 2226 other := make(Tags, len(a)) 2227 for i, t := range a { 2228 copy(buf, t.Key) 2229 other[i].Key, buf = buf[:len(t.Key)], buf[len(t.Key):] 2230 2231 copy(buf, t.Value) 2232 other[i].Value, buf = buf[:len(t.Value)], buf[len(t.Value):] 2233 } 2234 2235 return other 2236} 2237 2238// Fields represents a mapping between a Point's field names and their 2239// values. 2240type Fields map[string]interface{} 2241 2242// FieldIterator returns a FieldIterator that can be used to traverse the 2243// fields of a point without constructing the in-memory map. 2244func (p *point) FieldIterator() FieldIterator { 2245 p.Reset() 2246 return p 2247} 2248 2249type fieldIterator struct { 2250 start, end int 2251 key, keybuf []byte 2252 valueBuf []byte 2253 fieldType FieldType 2254} 2255 2256// Next indicates whether there any fields remaining. 2257func (p *point) Next() bool { 2258 p.it.start = p.it.end 2259 if p.it.start >= len(p.fields) { 2260 return false 2261 } 2262 2263 p.it.end, p.it.key = scanTo(p.fields, p.it.start, '=') 2264 if escape.IsEscaped(p.it.key) { 2265 p.it.keybuf = escape.AppendUnescaped(p.it.keybuf[:0], p.it.key) 2266 p.it.key = p.it.keybuf 2267 } 2268 2269 p.it.end, p.it.valueBuf = scanFieldValue(p.fields, p.it.end+1) 2270 p.it.end++ 2271 2272 if len(p.it.valueBuf) == 0 { 2273 p.it.fieldType = Empty 2274 return true 2275 } 2276 2277 c := p.it.valueBuf[0] 2278 2279 if c == '"' { 2280 p.it.fieldType = String 2281 return true 2282 } 2283 2284 if strings.IndexByte(`0123456789-.nNiIu`, c) >= 0 { 2285 if p.it.valueBuf[len(p.it.valueBuf)-1] == 'i' { 2286 p.it.fieldType = Integer 2287 p.it.valueBuf = p.it.valueBuf[:len(p.it.valueBuf)-1] 2288 } else if p.it.valueBuf[len(p.it.valueBuf)-1] == 'u' { 2289 p.it.fieldType = Unsigned 2290 p.it.valueBuf = p.it.valueBuf[:len(p.it.valueBuf)-1] 2291 } else { 2292 p.it.fieldType = Float 2293 } 2294 return true 2295 } 2296 2297 // to keep the same behavior that currently exists, default to boolean 2298 p.it.fieldType = Boolean 2299 return true 2300} 2301 2302// FieldKey returns the key of the current field. 2303func (p *point) FieldKey() []byte { 2304 return p.it.key 2305} 2306 2307// Type returns the FieldType of the current field. 2308func (p *point) Type() FieldType { 2309 return p.it.fieldType 2310} 2311 2312// StringValue returns the string value of the current field. 2313func (p *point) StringValue() string { 2314 return unescapeStringField(string(p.it.valueBuf[1 : len(p.it.valueBuf)-1])) 2315} 2316 2317// IntegerValue returns the integer value of the current field. 2318func (p *point) IntegerValue() (int64, error) { 2319 n, err := parseIntBytes(p.it.valueBuf, 10, 64) 2320 if err != nil { 2321 return 0, fmt.Errorf("unable to parse integer value %q: %v", p.it.valueBuf, err) 2322 } 2323 return n, nil 2324} 2325 2326// UnsignedValue returns the unsigned value of the current field. 2327func (p *point) UnsignedValue() (uint64, error) { 2328 n, err := parseUintBytes(p.it.valueBuf, 10, 64) 2329 if err != nil { 2330 return 0, fmt.Errorf("unable to parse unsigned value %q: %v", p.it.valueBuf, err) 2331 } 2332 return n, nil 2333} 2334 2335// BooleanValue returns the boolean value of the current field. 2336func (p *point) BooleanValue() (bool, error) { 2337 b, err := parseBoolBytes(p.it.valueBuf) 2338 if err != nil { 2339 return false, fmt.Errorf("unable to parse bool value %q: %v", p.it.valueBuf, err) 2340 } 2341 return b, nil 2342} 2343 2344// FloatValue returns the float value of the current field. 2345func (p *point) FloatValue() (float64, error) { 2346 f, err := parseFloatBytes(p.it.valueBuf, 64) 2347 if err != nil { 2348 return 0, fmt.Errorf("unable to parse floating point value %q: %v", p.it.valueBuf, err) 2349 } 2350 return f, nil 2351} 2352 2353// Reset resets the iterator to its initial state. 2354func (p *point) Reset() { 2355 p.it.fieldType = Empty 2356 p.it.key = nil 2357 p.it.valueBuf = nil 2358 p.it.start = 0 2359 p.it.end = 0 2360} 2361 2362// MarshalBinary encodes all the fields to their proper type and returns the binary 2363// representation 2364// NOTE: uint64 is specifically not supported due to potential overflow when we decode 2365// again later to an int64 2366// NOTE2: uint is accepted, and may be 64 bits, and is for some reason accepted... 2367func (p Fields) MarshalBinary() []byte { 2368 var b []byte 2369 keys := make([]string, 0, len(p)) 2370 2371 for k := range p { 2372 keys = append(keys, k) 2373 } 2374 2375 // Not really necessary, can probably be removed. 2376 sort.Strings(keys) 2377 2378 for i, k := range keys { 2379 if i > 0 { 2380 b = append(b, ',') 2381 } 2382 b = appendField(b, k, p[k]) 2383 } 2384 2385 return b 2386} 2387 2388func appendField(b []byte, k string, v interface{}) []byte { 2389 b = append(b, []byte(escape.String(k))...) 2390 b = append(b, '=') 2391 2392 // check popular types first 2393 switch v := v.(type) { 2394 case float64: 2395 b = strconv.AppendFloat(b, v, 'f', -1, 64) 2396 case int64: 2397 b = strconv.AppendInt(b, v, 10) 2398 b = append(b, 'i') 2399 case string: 2400 b = append(b, '"') 2401 b = append(b, []byte(EscapeStringField(v))...) 2402 b = append(b, '"') 2403 case bool: 2404 b = strconv.AppendBool(b, v) 2405 case int32: 2406 b = strconv.AppendInt(b, int64(v), 10) 2407 b = append(b, 'i') 2408 case int16: 2409 b = strconv.AppendInt(b, int64(v), 10) 2410 b = append(b, 'i') 2411 case int8: 2412 b = strconv.AppendInt(b, int64(v), 10) 2413 b = append(b, 'i') 2414 case int: 2415 b = strconv.AppendInt(b, int64(v), 10) 2416 b = append(b, 'i') 2417 case uint64: 2418 b = strconv.AppendUint(b, v, 10) 2419 b = append(b, 'u') 2420 case uint32: 2421 b = strconv.AppendInt(b, int64(v), 10) 2422 b = append(b, 'i') 2423 case uint16: 2424 b = strconv.AppendInt(b, int64(v), 10) 2425 b = append(b, 'i') 2426 case uint8: 2427 b = strconv.AppendInt(b, int64(v), 10) 2428 b = append(b, 'i') 2429 case uint: 2430 // TODO: 'uint' should be converted to writing as an unsigned integer, 2431 // but we cannot since that would break backwards compatibility. 2432 b = strconv.AppendInt(b, int64(v), 10) 2433 b = append(b, 'i') 2434 case float32: 2435 b = strconv.AppendFloat(b, float64(v), 'f', -1, 32) 2436 case []byte: 2437 b = append(b, v...) 2438 case nil: 2439 // skip 2440 default: 2441 // Can't determine the type, so convert to string 2442 b = append(b, '"') 2443 b = append(b, []byte(EscapeStringField(fmt.Sprintf("%v", v)))...) 2444 b = append(b, '"') 2445 2446 } 2447 2448 return b 2449} 2450 2451// ValidKeyToken returns true if the token used for measurement, tag key, or tag 2452// value is a valid unicode string and only contains printable, non-replacement characters. 2453func ValidKeyToken(s string) bool { 2454 if !utf8.ValidString(s) { 2455 return false 2456 } 2457 for _, r := range s { 2458 if !unicode.IsPrint(r) || r == unicode.ReplacementChar { 2459 return false 2460 } 2461 } 2462 return true 2463} 2464 2465// ValidKeyTokens returns true if the measurement name and all tags are valid. 2466func ValidKeyTokens(name string, tags Tags) bool { 2467 if !ValidKeyToken(name) { 2468 return false 2469 } 2470 for _, tag := range tags { 2471 if !ValidKeyToken(string(tag.Key)) || !ValidKeyToken(string(tag.Value)) { 2472 return false 2473 } 2474 } 2475 return true 2476} 2477