utils.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package influxdbsubscribe
  15. import (
  16. "bytes"
  17. "fmt"
  18. "math"
  19. "reflect"
  20. "strconv"
  21. "strings"
  22. "time"
  23. "unsafe"
  24. )
  25. var (
  26. Codes = map[byte][]byte{
  27. ',': []byte(`\,`),
  28. '"': []byte(`\"`),
  29. ' ': []byte(`\ `),
  30. '=': []byte(`\=`),
  31. }
  32. codesStr = map[string]string{}
  33. )
  34. func init() {
  35. for k, v := range Codes {
  36. codesStr[string(k)] = string(v)
  37. }
  38. }
  39. const (
  40. // MinNanoTime is the minumum time that can be represented.
  41. //
  42. // 1677-09-21 00:12:43.145224194 +0000 UTC
  43. //
  44. // The two lowest minimum integers are used as sentinel values. The
  45. // minimum value needs to be used as a value lower than any other value for
  46. // comparisons and another separate value is needed to act as a sentinel
  47. // default value that is unusable by the user, but usable internally.
  48. // Because these two values need to be used for a special purpose, we do
  49. // not allow users to write points at these two times.
  50. MinNanoTime = int64(math.MinInt64) + 2
  51. // MaxNanoTime is the maximum time that can be represented.
  52. //
  53. // 2262-04-11 23:47:16.854775806 +0000 UTC
  54. //
  55. // The highest time represented by a nanosecond needs to be used for an
  56. // exclusive range in the shard group, so the maximum time needs to be one
  57. // less than the possible maximum number of nanoseconds representable by an
  58. // int64 so that we don't lose a point at that one time.
  59. MaxNanoTime = int64(math.MaxInt64) - 1
  60. )
  61. var (
  62. minNanoTime = time.Unix(0, MinNanoTime).UTC()
  63. maxNanoTime = time.Unix(0, MaxNanoTime).UTC()
  64. // ErrTimeOutOfRange gets returned when time is out of the representable range using int64 nanoseconds since the epoch.
  65. ErrTimeOutOfRange = fmt.Errorf("time outside range %d - %d", MinNanoTime, MaxNanoTime)
  66. )
  67. // parseIntBytes is a zero-alloc wrapper around strconv.ParseInt.
  68. func parseIntBytes(b []byte, base int, bitSize int) (i int64, err error) {
  69. s := unsafeBytesToString(b)
  70. return strconv.ParseInt(s, base, bitSize)
  71. }
  72. // unsafeBytesToString converts a []byte to a string without a heap allocation.
  73. //
  74. // It is unsafe, and is intended to prepare input to short-lived functions
  75. // that require strings.
  76. func unsafeBytesToString(in []byte) string {
  77. src := *(*reflect.SliceHeader)(unsafe.Pointer(&in))
  78. dst := reflect.StringHeader{
  79. Data: src.Data,
  80. Len: src.Len,
  81. }
  82. s := *(*string)(unsafe.Pointer(&dst))
  83. return s
  84. }
  85. // parseFloatBytes is a zero-alloc wrapper around strconv.ParseFloat.
  86. func parseFloatBytes(b []byte, bitSize int) (float64, error) {
  87. s := unsafeBytesToString(b)
  88. return strconv.ParseFloat(s, bitSize)
  89. }
  90. // parseBoolBytes is a zero-alloc wrapper around strconv.ParseBool.
  91. func parseBoolBytes(b []byte) (bool, error) {
  92. return strconv.ParseBool(unsafeBytesToString(b))
  93. }
  94. func Unescape(in []byte) []byte {
  95. if len(in) == 0 {
  96. return nil
  97. }
  98. if bytes.IndexByte(in, '\\') == -1 {
  99. return in
  100. }
  101. i := 0
  102. inLen := len(in)
  103. var out []byte
  104. for {
  105. if i >= inLen {
  106. break
  107. }
  108. if in[i] == '\\' && i+1 < inLen {
  109. switch in[i+1] {
  110. case ',':
  111. out = append(out, ',')
  112. i += 2
  113. continue
  114. case '"':
  115. out = append(out, '"')
  116. i += 2
  117. continue
  118. case ' ':
  119. out = append(out, ' ')
  120. i += 2
  121. continue
  122. case '=':
  123. out = append(out, '=')
  124. i += 2
  125. continue
  126. }
  127. }
  128. out = append(out, in[i])
  129. i += 1
  130. }
  131. return out
  132. }
  133. func UnescapeString(in string) string {
  134. if strings.IndexByte(in, '\\') == -1 {
  135. return in
  136. }
  137. for b, esc := range codesStr {
  138. in = strings.Replace(in, esc, b, -1)
  139. }
  140. return in
  141. }
  142. func GetString(in string) string {
  143. for b, esc := range codesStr {
  144. in = strings.Replace(in, b, esc, -1)
  145. }
  146. return in
  147. }
  148. // SafeCalcTime safely calculates the time given. Will return error if the time is outside the
  149. // supported range.
  150. func SafeCalcTime(timestamp int64, precision string) (time.Time, error) {
  151. mult := GetPrecisionMultiplier(precision)
  152. if t, ok := safeSignedMult(timestamp, mult); ok {
  153. tme := time.Unix(0, t).UTC()
  154. return tme, CheckTime(tme)
  155. }
  156. return time.Time{}, ErrTimeOutOfRange
  157. }
  158. // CheckTime checks that a time is within the safe range.
  159. func CheckTime(t time.Time) error {
  160. if t.Before(minNanoTime) || t.After(maxNanoTime) {
  161. return ErrTimeOutOfRange
  162. }
  163. return nil
  164. }
  165. // Perform the multiplication and check to make sure it didn't overflow.
  166. func safeSignedMult(a, b int64) (int64, bool) {
  167. if a == 0 || b == 0 || a == 1 || b == 1 {
  168. return a * b, true
  169. }
  170. if a == MinNanoTime || b == MaxNanoTime {
  171. return 0, false
  172. }
  173. c := a * b
  174. return c, c/b == a
  175. }
  176. const escapeChars = `," =`
  177. func IsEscaped(b []byte) bool {
  178. for len(b) > 0 {
  179. i := bytes.IndexByte(b, '\\')
  180. if i < 0 {
  181. return false
  182. }
  183. if i+1 < len(b) && strings.IndexByte(escapeChars, b[i+1]) >= 0 {
  184. return true
  185. }
  186. b = b[i+1:]
  187. }
  188. return false
  189. }
  190. func AppendUnescaped(dst, src []byte) []byte {
  191. var pos int
  192. for len(src) > 0 {
  193. next := bytes.IndexByte(src[pos:], '\\')
  194. if next < 0 || pos+next+1 >= len(src) {
  195. return append(dst, src...)
  196. }
  197. if pos+next+1 < len(src) && strings.IndexByte(escapeChars, src[pos+next+1]) >= 0 {
  198. if pos+next > 0 {
  199. dst = append(dst, src[:pos+next]...)
  200. }
  201. src = src[pos+next+1:]
  202. pos = 0
  203. } else {
  204. pos += next + 1
  205. }
  206. }
  207. return dst
  208. }