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  }