func (w *Watcher) handleFile(path string) { if !w.wantFile(path) { return } release, existed, err := flock.New(path) if !existed { w.debug("File didn't exist flock will have created it. I am too chicken to delete things though.. ") } if err != nil { w.debug("Lock failed") } else { defer release.Release() } if w.Config.Paranoia > NoParanoia { for w.paranoiaWait(path) { time.Sleep(250 * time.Millisecond) } } actions_ok := w.actions_for_file(path) _, filename := filepath.Split(path) already_archived := false archive := func(dir string) { if !already_archived { w.report_action("Archiving ", path, " to ", dir) e := gomv.MoveFile(path, dir+string(os.PathSeparator)+filename) if e != nil { w.error(e) } else { already_archived = true } } } if !actions_ok && w.Config.ErrorDir != "" { archive(w.Config.ErrorDir) } if w.Config.ArchiveDir != "" { archive(w.Config.ArchiveDir) } if w.Config.AfterFileAction != nil { w.Config.AfterFileAction(path) } if v := w.test_opts["exit_after_one"]; v { w.Close() } }
// newPersistence returns a newly allocated persistence backed by local disk storage, ready to use. func newPersistence(basePath string, dirty, pedanticChecks bool, shouldSync syncStrategy) (*persistence, error) { dirtyPath := filepath.Join(basePath, dirtyFileName) versionPath := filepath.Join(basePath, versionFileName) if versionData, err := ioutil.ReadFile(versionPath); err == nil { if persistedVersion, err := strconv.Atoi(strings.TrimSpace(string(versionData))); err != nil { return nil, fmt.Errorf("cannot parse content of %s: %s", versionPath, versionData) } else if persistedVersion != Version { return nil, fmt.Errorf("found storage version %d on disk, need version %d - please wipe storage or run a version of Prometheus compatible with storage version %d", persistedVersion, Version, persistedVersion) } } else if os.IsNotExist(err) { // No version file found. Let's create the directory (in case // it's not there yet) and then check if it is actually // empty. If not, we have found an old storage directory without // version file, so we have to bail out. if err := os.MkdirAll(basePath, 0700); err != nil { return nil, err } fis, err := ioutil.ReadDir(basePath) if err != nil { return nil, err } if len(fis) > 0 { return nil, fmt.Errorf("could not detect storage version on disk, assuming version 0, need version %d - please wipe storage or run a version of Prometheus compatible with storage version 0", Version) } // Finally we can write our own version into a new version file. file, err := os.Create(versionPath) if err != nil { return nil, err } defer file.Close() if _, err := fmt.Fprintf(file, "%d\n", Version); err != nil { return nil, err } } else { return nil, err } fLock, dirtyfileExisted, err := flock.New(dirtyPath) if err != nil { log.Errorf("Could not lock %s, Prometheus already running?", dirtyPath) return nil, err } if dirtyfileExisted { dirty = true } archivedFingerprintToMetrics, err := index.NewFingerprintMetricIndex(basePath) if err != nil { return nil, err } archivedFingerprintToTimeRange, err := index.NewFingerprintTimeRangeIndex(basePath) if err != nil { return nil, err } p := &persistence{ basePath: basePath, archivedFingerprintToMetrics: archivedFingerprintToMetrics, archivedFingerprintToTimeRange: archivedFingerprintToTimeRange, indexingQueue: make(chan indexingOp, indexingQueueCapacity), indexingStopped: make(chan struct{}), indexingFlush: make(chan chan int), indexingQueueLength: prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: subsystem, Name: "indexing_queue_length", Help: "The number of metrics waiting to be indexed.", }), indexingQueueCapacity: prometheus.MustNewConstMetric( prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, "indexing_queue_capacity"), "The capacity of the indexing queue.", nil, nil, ), prometheus.GaugeValue, float64(indexingQueueCapacity), ), indexingBatchSizes: prometheus.NewSummary( prometheus.SummaryOpts{ Namespace: namespace, Subsystem: subsystem, Name: "indexing_batch_sizes", Help: "Quantiles for indexing batch sizes (number of metrics per batch).", }, ), indexingBatchDuration: prometheus.NewSummary( prometheus.SummaryOpts{ Namespace: namespace, Subsystem: subsystem, Name: "indexing_batch_duration_milliseconds", Help: "Quantiles for batch indexing duration in milliseconds.", }, ), checkpointDuration: prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: subsystem, Name: "checkpoint_duration_milliseconds", Help: "The duration (in milliseconds) it took to checkpoint in-memory metrics and head chunks.", }), dirtyCounter: prometheus.NewCounter(prometheus.CounterOpts{ Namespace: namespace, Subsystem: subsystem, Name: "inconsistencies_total", Help: "A counter incremented each time an inconsistency in the local storage is detected. If this is greater zero, restart the server as soon as possible.", }), dirty: dirty, pedanticChecks: pedanticChecks, dirtyFileName: dirtyPath, fLock: fLock, shouldSync: shouldSync, // Create buffers of length 3*chunkLenWithHeader by default because that is still reasonably small // and at the same time enough for many uses. The contract is to never return buffer smaller than // that to the pool so that callers can rely on a minimum buffer size. bufPool: sync.Pool{New: func() interface{} { return make([]byte, 0, 3*chunkLenWithHeader) }}, } if p.dirty { // Blow away the label indexes. We'll rebuild them later. if err := index.DeleteLabelPairFingerprintIndex(basePath); err != nil { return nil, err } if err := index.DeleteLabelNameLabelValuesIndex(basePath); err != nil { return nil, err } } labelPairToFingerprints, err := index.NewLabelPairFingerprintIndex(basePath) if err != nil { return nil, err } labelNameToLabelValues, err := index.NewLabelNameLabelValuesIndex(basePath) if err != nil { return nil, err } p.labelPairToFingerprints = labelPairToFingerprints p.labelNameToLabelValues = labelNameToLabelValues return p, nil }