diff --git a/db.go b/db.go index 28cb14f3..64387dd6 100644 --- a/db.go +++ b/db.go @@ -550,7 +550,7 @@ func (db *DB) reload(deleteable ...string) (err error) { if len(blocks) == 0 { return nil } - maxt := blocks[len(blocks)-1].Meta().MaxTime + maxt := blocks[len(blocks)-1].Meta().MaxTime + 1 return errors.Wrap(db.head.Truncate(maxt), "head truncate failed") } @@ -805,9 +805,12 @@ func (db *DB) Querier(mint, maxt int64) (Querier, error) { return sq, nil } +// Returns a closed time interval that contains t, with its lower boundary +// aligned on a multiple of width. The upper boundary is such that the next +// interval is contiguous without overlapping. func rangeForTimestamp(t int64, width int64) (mint, maxt int64) { mint = (t / width) * width - return mint, mint + width + return mint, mint + width - 1 } // Delete implements deletion of metrics. It only has atomicity guarantees on a per-block basis. diff --git a/head.go b/head.go index 2c7c7ec3..7926cdf9 100644 --- a/head.go +++ b/head.go @@ -1133,7 +1133,10 @@ func (s *memSeries) cut(mint int64) *memChunk { // Set upper bound on when the next chunk must be started. An earlier timestamp // may be chosen dynamically at a later point. - _, s.nextAt = rangeForTimestamp(mint, s.chunkRange) + _, maxt := rangeForTimestamp(mint, s.chunkRange) + // rangeForTimestamp() returns the maximum timestamp for the previous + // chunk; we want to cut right after that, so we add 1 millisecond + s.nextAt = maxt + 1 app, err := c.chunk.Appender() if err != nil {