github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ts/timespan.go (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package ts 12 13 import "fmt" 14 15 // QueryTimespan describes the time range information for a query - the start 16 // and end bounds of the query, along with the requested duration of individual 17 // samples to be returned. Methods of this structure are mutating. 18 type QueryTimespan struct { 19 StartNanos int64 20 EndNanos int64 21 NowNanos int64 22 SampleDurationNanos int64 23 } 24 25 // width returns the width of the timespan: the distance between its start and 26 // and end bounds. 27 func (qt *QueryTimespan) width() int64 { 28 return qt.EndNanos - qt.StartNanos 29 } 30 31 // moveForward modifies the timespan so that it has the same width, but 32 // both StartNanos and EndNanos is moved forward by the specified number of 33 // nanoseconds. 34 func (qt *QueryTimespan) moveForward(forwardNanos int64) { 35 qt.StartNanos += forwardNanos 36 qt.EndNanos += forwardNanos 37 } 38 39 // expand modifies the timespan so that its width is expanded *on each side* 40 // by the supplied size; the resulting width will be (2 * size) larger than the 41 // original width. 42 func (qt *QueryTimespan) expand(size int64) { 43 qt.StartNanos -= size 44 qt.EndNanos += size 45 } 46 47 // normalize modifies startNanos and endNanos so that they are exact multiples 48 // of the sampleDuration. Values are modified by subtraction. 49 func (qt *QueryTimespan) normalize() { 50 qt.StartNanos -= qt.StartNanos % qt.SampleDurationNanos 51 qt.EndNanos -= qt.EndNanos % qt.SampleDurationNanos 52 } 53 54 // verifyBounds returns an error if the bounds of this QueryTimespan are 55 // incorrect; currently, this only occurs if the width is negative. 56 func (qt *QueryTimespan) verifyBounds() error { 57 if qt.StartNanos > qt.EndNanos { 58 return fmt.Errorf("startNanos %d was later than endNanos %d", qt.StartNanos, qt.EndNanos) 59 } 60 return nil 61 } 62 63 // verifyDiskResolution returns an error if this timespan is not suitable for 64 // querying the supplied disk resolution. 65 func (qt *QueryTimespan) verifyDiskResolution(diskResolution Resolution) error { 66 resolutionSampleDuration := diskResolution.SampleDuration() 67 // Verify that sampleDuration is a multiple of 68 // diskResolution.SampleDuration(). 69 if qt.SampleDurationNanos < resolutionSampleDuration { 70 return fmt.Errorf( 71 "sampleDuration %d was not less that queryResolution.SampleDuration %d", 72 qt.SampleDurationNanos, 73 resolutionSampleDuration, 74 ) 75 } 76 if qt.SampleDurationNanos%resolutionSampleDuration != 0 { 77 return fmt.Errorf( 78 "sampleDuration %d is not a multiple of queryResolution.SampleDuration %d", 79 qt.SampleDurationNanos, 80 resolutionSampleDuration, 81 ) 82 } 83 return nil 84 } 85 86 // adjustForCurrentTime adjusts the passed query timespan in order to prevent 87 // certain artifacts which can occur when querying in the very recent past. 88 func (qt *QueryTimespan) adjustForCurrentTime(diskResolution Resolution) error { 89 // Disallow queries for the sample period containing the current system time 90 // and any later periods. This prevents returning "incomplete" data for sample 91 // periods where new data may yet be recorded, which in turn prevents an odd 92 // user experience where graphs of recent metric data have a precipitous "dip" 93 // at latest timestamp. 94 cutoff := qt.NowNanos - qt.SampleDurationNanos 95 96 // Do not allow queries in the future. 97 if qt.StartNanos > cutoff { 98 return fmt.Errorf( 99 "cannot query time series in the future (start time %d was greater than current clock %d", 100 qt.StartNanos, 101 qt.NowNanos, 102 ) 103 } 104 if qt.EndNanos > cutoff { 105 qt.EndNanos = cutoff 106 } 107 108 return nil 109 }