func (d *dataAccess) getIncident(incidentId int64, conn redis.Conn) (*models.IncidentState, error) { b, err := redis.Bytes(conn.Do("GET", incidentStateKey(incidentId))) if err != nil { return nil, slog.Wrap(err) } state := &models.IncidentState{} if err = json.Unmarshal(b, state); err != nil { return nil, slog.Wrap(err) } return state, nil }
func saveIncident(id uint64, i *models.Incident, conn redis.Conn) error { raw, err := json.Marshal(i) if err != nil { return err } if _, err = conn.Do("HSET", "incidents", id, raw); err != nil { return err } if _, err = conn.Do("ZADD", "incidentsByStart", i.Start.UTC().Unix(), id); err != nil { return err } return nil }
func (d *dataAccess) getLatestIncident(ak models.AlertKey, conn redis.Conn) (*models.IncidentState, error) { id, err := redis.Int64(conn.Do("LINDEX", incidentsForAlertKeyKey(ak), 0)) if err != nil { if err == redis.ErrNil { return nil, nil } return nil, slog.Wrap(err) } inc, err := d.getIncident(id, conn) if err != nil { return nil, slog.Wrap(err) } return inc, nil }
func (d *dataAccess) transact(conn redis.Conn, f func() error) error { if !d.isRedis { return f() } if _, err := conn.Do("MULTI"); err != nil { return slog.Wrap(err) } if err := f(); err != nil { return slog.Wrap(err) } if _, err := conn.Do("EXEC"); err != nil { return slog.Wrap(err) } return nil }
func incrementRedisCounter(data []byte, addr string, conn redis.Conn) { if len(data) < 5 { slog.Errorf("Insufficient data for increment from %s.", addr) return } r := bytes.NewReader(data) var i int32 err := binary.Read(r, binary.BigEndian, &i) if err != nil { slog.Error(err) return } mts := string(data[4:]) if _, err = conn.Do("HINCRBY", RedisCountersKey, mts, i); err != nil { slog.Errorf("Error incrementing counter %s by %d. From %s. %s", mts, i, addr, err) } }
func getSilences(ids []string, conn redis.Conn) ([]*models.Silence, error) { args := make([]interface{}, len(ids)+1) args[0] = silenceHash for i := range ids { args[i+1] = ids[i] } jsons, err := redis.Strings(conn.Do("HMGET", args...)) if err != nil { log.Fatal(err, args) return nil, err } silences := make([]*models.Silence, 0, len(jsons)) for _, j := range jsons { s := &models.Silence{} if err := json.Unmarshal([]byte(j), s); err != nil { return nil, err } silences = append(silences, s) } return silences, nil }
func (d *dataAccess) incidentMultiGet(conn redis.Conn, ids []int64) ([]*models.IncidentState, error) { if len(ids) == 0 { return nil, nil } // get all incident json keys args := make([]interface{}, 0, len(ids)) for _, id := range ids { args = append(args, incidentStateKey(id)) } jsons, err := redis.Strings(conn.Do("MGET", args...)) if err != nil { return nil, slog.Wrap(err) } results := make([]*models.IncidentState, 0, len(jsons)) for _, j := range jsons { state := &models.IncidentState{} if err = json.Unmarshal([]byte(j), state); err != nil { return nil, slog.Wrap(err) } results = append(results, state) } return results, nil }
// zpop pops a value from the ZSET key using WATCH/MULTI/EXEC commands. func zpop(c redis.Conn, key string) (result string, err error) { defer func() { // Return connection to normal state on error. if err != nil { c.Do("DISCARD") } }() // Loop until transaction is successful. for { if _, err := c.Do("WATCH", key); err != nil { return "", err } members, err := redis.Strings(c.Do("ZRANGE", key, 0, 0)) if err != nil { return "", err } if len(members) != 1 { return "", redis.ErrNil } c.Send("MULTI") c.Send("ZREM", key, members[0]) queued, err := c.Do("EXEC") if err != nil { return "", err } if queued != nil { result = members[0] break } } return result, nil }