github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/tools/blocksconvert/plan_file.go (about)

     1  package blocksconvert
     2  
     3  import (
     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  
    19  type 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  
    32  func (pe *PlanEntry) Reset() {
    33  	*pe = PlanEntry{}
    34  }
    35  
    36  // Returns true and "base name" or false and empty string.
    37  func 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  
    52  func 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  
    64  func StartingFilename(planBaseName string, t time.Time) string {
    65  	return fmt.Sprintf("%s.starting.%d", planBaseName, t.Unix())
    66  }
    67  
    68  func ProgressFilename(planBaseName string, t time.Time) string {
    69  	return fmt.Sprintf("%s.inprogress.%d", planBaseName, t.Unix())
    70  }
    71  
    72  var progress = regexp.MustCompile(`^(.+)\.(starting|progress|inprogress)\.(\d+)$`)
    73  
    74  func 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  
    88  func FinishedFilename(planBaseName string, id string) string {
    89  	return fmt.Sprintf("%s.finished.%s", planBaseName, id)
    90  }
    91  
    92  var finished = regexp.MustCompile(`^(.+)\.finished\.([a-zA-Z0-9]+)$`)
    93  
    94  func 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  
   103  func ErrorFilename(planBaseName string) string {
   104  	return planBaseName + ".error"
   105  }
   106  
   107  func IsErrorFilename(name string) (bool, string) {
   108  	if strings.HasSuffix(name, ".error") {
   109  		return true, name[:len(name)-len(".error")]
   110  	}
   111  	return false, ""
   112  }