bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/bosun/database/search_data.go (about) 1 package database 2 3 import ( 4 "fmt" 5 "strconv" 6 7 "bosun.org/opentsdb" 8 "bosun.org/slog" 9 "bosun.org/util" 10 "github.com/garyburd/redigo/redis" 11 ) 12 13 /* 14 Search data in redis: 15 16 Metrics by tags: 17 search:metrics:{tagk}={tagv} -> hash of metric name to timestamp 18 19 Tag keys by metric: 20 search:tagk:{metric} -> hash of tag key to timestamp 21 22 Tag Values By metric/tag key 23 search:tagv:{metric}:{tagk} -> hash of tag value to timestamp 24 metric "__all__" is a special key that will hold all values for the tag key, regardless of metric 25 26 All Metrics: 27 search:allMetrics -> hash of metric name to timestamp 28 29 search:mts:{metric} -> all tag sets for a metric. Hash with time stamps 30 */ 31 32 const Search_All = "__all__" 33 const searchAllMetricsKey = "search:allMetrics" 34 35 func searchMetricKey(tagK, tagV string) string { 36 return fmt.Sprintf("search:metrics:%s=%s", tagK, tagV) 37 } 38 func searchTagkKey(metric string) string { 39 return fmt.Sprintf("search:tagk:%s", metric) 40 } 41 func searchTagvKey(metric, tagK string) string { 42 return fmt.Sprintf("search:tagv:%s:%s", metric, tagK) 43 } 44 func searchMetricTagSetKey(metric string) string { 45 return fmt.Sprintf("search:mts:%s", metric) 46 } 47 48 func (d *dataAccess) Search() SearchDataAccess { 49 return d 50 } 51 52 func (d *dataAccess) AddMetricForTag(tagK, tagV, metric string, time int64) error { 53 conn := d.Get() 54 defer conn.Close() 55 56 _, err := conn.Do("HSET", searchMetricKey(tagK, tagV), metric, time) 57 return slog.Wrap(err) 58 } 59 60 func (d *dataAccess) GetMetricsForTag(tagK, tagV string) (map[string]int64, error) { 61 conn := d.Get() 62 defer conn.Close() 63 64 return stringInt64Map(conn.Do("HGETALL", searchMetricKey(tagK, tagV))) 65 } 66 67 func stringInt64Map(d interface{}, err error) (map[string]int64, error) { 68 if err != nil { 69 return nil, err 70 } 71 vals, err := redis.Strings(d, err) 72 if err != nil { 73 return nil, err 74 } 75 result := make(map[string]int64) 76 for i := 1; i < len(vals); i += 2 { 77 time, _ := strconv.ParseInt(vals[i], 10, 64) 78 result[vals[i-1]] = time 79 } 80 return result, slog.Wrap(err) 81 } 82 83 func (d *dataAccess) AddTagKeyForMetric(metric, tagK string, time int64) error { 84 conn := d.Get() 85 defer conn.Close() 86 87 _, err := conn.Do("HSET", searchTagkKey(metric), tagK, time) 88 return slog.Wrap(err) 89 } 90 91 func (d *dataAccess) GetTagKeysForMetric(metric string) (map[string]int64, error) { 92 conn := d.Get() 93 defer conn.Close() 94 95 return stringInt64Map(conn.Do("HGETALL", searchTagkKey(metric))) 96 } 97 98 func (d *dataAccess) AddMetric(metric string, time int64) error { 99 conn := d.Get() 100 defer conn.Close() 101 102 _, err := conn.Do("HSET", searchAllMetricsKey, metric, time) 103 return slog.Wrap(err) 104 } 105 func (d *dataAccess) GetAllMetrics() (map[string]int64, error) { 106 conn := d.Get() 107 defer conn.Close() 108 109 return stringInt64Map(conn.Do("HGETALL", searchAllMetricsKey)) 110 } 111 112 func (d *dataAccess) AddTagValue(metric, tagK, tagV string, time int64) error { 113 conn := d.Get() 114 defer conn.Close() 115 116 _, err := conn.Do("HSET", searchTagvKey(metric, tagK), tagV, time) 117 return slog.Wrap(err) 118 } 119 120 func (d *dataAccess) GetTagValues(metric, tagK string) (map[string]int64, error) { 121 conn := d.Get() 122 defer conn.Close() 123 124 return stringInt64Map(conn.Do("HGETALL", searchTagvKey(metric, tagK))) 125 } 126 127 func (d *dataAccess) AddMetricTagSet(metric, tagSet string, time int64) error { 128 conn := d.Get() 129 defer conn.Close() 130 131 _, err := conn.Do("HSET", searchMetricTagSetKey(metric), tagSet, time) 132 return slog.Wrap(err) 133 } 134 135 func (d *dataAccess) GetMetricTagSets(metric string, tags opentsdb.TagSet) (map[string]int64, error) { 136 conn := d.Get() 137 defer conn.Close() 138 139 var cursor = "0" 140 result := map[string]int64{} 141 142 for { 143 vals, err := redis.Values(conn.Do(d.HSCAN(), searchMetricTagSetKey(metric), cursor)) 144 if err != nil { 145 return nil, slog.Wrap(err) 146 } 147 cursor, err = redis.String(vals[0], nil) 148 if err != nil { 149 return nil, slog.Wrap(err) 150 } 151 mtss, err := stringInt64Map(vals[1], nil) 152 if err != nil { 153 return nil, slog.Wrap(err) 154 } 155 for mts, t := range mtss { 156 ts, err := opentsdb.ParseTags(mts) 157 if err != nil { 158 return nil, slog.Wrap(err) 159 } 160 if ts.Subset(tags) { 161 result[mts] = t 162 } 163 } 164 if cursor == "" || cursor == "0" { 165 break 166 } 167 } 168 return result, nil 169 } 170 171 func (d *dataAccess) BackupLastInfos(m map[string]map[string]*LastInfo) error { 172 conn := d.Get() 173 defer conn.Close() 174 175 dat, err := util.MarshalGzipJson(m) 176 if err != nil { 177 return slog.Wrap(err) 178 } 179 _, err = conn.Do("SET", "search:last", dat) 180 return slog.Wrap(err) 181 } 182 183 func (d *dataAccess) LoadLastInfos() (map[string]map[string]*LastInfo, error) { 184 conn := d.Get() 185 defer conn.Close() 186 187 b, err := redis.Bytes(conn.Do("GET", "search:last")) 188 if err != nil { 189 return nil, slog.Wrap(err) 190 } 191 var m map[string]map[string]*LastInfo 192 err = util.UnmarshalGzipJson(b, &m) 193 if err != nil { 194 return nil, slog.Wrap(err) 195 } 196 return m, nil 197 } 198 199 //This function not exposed on any public interface. See cmd/bosun/database/test/util/purge_search_data.go for usage. 200 func (d *dataAccess) PurgeSearchData(metric string, noop bool) error { 201 conn := d.Get() 202 defer conn.Close() 203 204 tagKeys, err := d.GetTagKeysForMetric(metric) 205 if err != nil { 206 return err 207 } 208 fmt.Println("HDEL", searchAllMetricsKey) 209 if !noop { 210 _, err = conn.Do("HDEL", searchAllMetricsKey, metric) 211 if err != nil { 212 return err 213 } 214 } 215 hashesToDelete := []string{ 216 searchMetricTagSetKey(metric), 217 searchTagkKey(metric), 218 } 219 for tagk := range tagKeys { 220 hashesToDelete = append(hashesToDelete, searchTagvKey(metric, tagk)) 221 } 222 cmd := d.HCLEAR() 223 for _, hash := range hashesToDelete { 224 fmt.Println(cmd, hash) 225 if !noop { 226 _, err = conn.Do(cmd, hash) 227 if err != nil { 228 return err 229 } 230 } 231 } 232 return nil 233 }