1package blocksconvert 2 3import ( 4 "compress/gzip" 5 "fmt" 6 "io" 7 "regexp" 8 "strconv" 9 "strings" 10 "time" 11 12 "github.com/golang/snappy" 13) 14 15// Plan file describes which series must be included in a block for given user and day. 16// It consists of JSON objects, each written on its own line. 17// Plan file starts with single header, many plan entries and single footer. 18 19type PlanEntry struct { 20 // Header 21 User string `json:"user,omitempty"` 22 DayIndex int `json:"day_index,omitempty"` 23 24 // Entries 25 SeriesID string `json:"sid,omitempty"` 26 Chunks []string `json:"cs,omitempty"` 27 28 // Footer 29 Complete bool `json:"complete,omitempty"` 30} 31 32func (pe *PlanEntry) Reset() { 33 *pe = PlanEntry{} 34} 35 36// Returns true and "base name" or false and empty string. 37func IsPlanFilename(name string) (bool, string) { 38 switch { 39 case strings.HasSuffix(name, ".plan.gz"): 40 return true, name[:len(name)-len(".plan.gz")] 41 42 case strings.HasSuffix(name, ".plan.snappy"): 43 return true, name[:len(name)-len(".plan.snappy")] 44 45 case strings.HasSuffix(name, ".plan"): 46 return true, name[:len(name)-len(".plan")] 47 } 48 49 return false, "" 50} 51 52func PreparePlanFileReader(planFile string, in io.Reader) (io.Reader, error) { 53 switch { 54 case strings.HasSuffix(planFile, ".snappy"): 55 return snappy.NewReader(in), nil 56 57 case strings.HasSuffix(planFile, ".gz"): 58 return gzip.NewReader(in) 59 } 60 61 return in, nil 62} 63 64func StartingFilename(planBaseName string, t time.Time) string { 65 return fmt.Sprintf("%s.starting.%d", planBaseName, t.Unix()) 66} 67 68func ProgressFilename(planBaseName string, t time.Time) string { 69 return fmt.Sprintf("%s.inprogress.%d", planBaseName, t.Unix()) 70} 71 72var progress = regexp.MustCompile(`^(.+)\.(starting|progress|inprogress)\.(\d+)$`) 73 74func IsProgressFilename(name string) (bool, string, time.Time) { 75 m := progress.FindStringSubmatch(name) 76 if len(m) == 0 { 77 return false, "", time.Time{} 78 } 79 80 ts, err := strconv.ParseInt(m[3], 10, 64) 81 if err != nil { 82 return false, "", time.Time{} 83 } 84 85 return true, m[1], time.Unix(ts, 0) 86} 87 88func FinishedFilename(planBaseName string, id string) string { 89 return fmt.Sprintf("%s.finished.%s", planBaseName, id) 90} 91 92var finished = regexp.MustCompile(`^(.+)\.finished\.([a-zA-Z0-9]+)$`) 93 94func IsFinishedFilename(name string) (bool, string, string) { 95 m := finished.FindStringSubmatch(name) 96 if len(m) == 0 { 97 return false, "", "" 98 } 99 100 return true, m[1], m[2] 101} 102 103func ErrorFilename(planBaseName string) string { 104 return planBaseName + ".error" 105} 106 107func IsErrorFilename(name string) (bool, string) { 108 if strings.HasSuffix(name, ".error") { 109 return true, name[:len(name)-len(".error")] 110 } 111 return false, "" 112} 113