@@ -75,6 +75,9 @@ type Head struct {
75
75
symbols map [string ]struct {}
76
76
values map [string ]stringset // label names to possible values
77
77
78
+ deletedMtx sync.Mutex
79
+ deleted map [uint64 ]int // Deleted series, and what WAL segment they must be kept until.
80
+
78
81
postings * index.MemPostings // postings lists for terms
79
82
}
80
83
@@ -234,6 +237,7 @@ func NewHead(r prometheus.Registerer, l log.Logger, wal *wal.WAL, chunkRange int
234
237
values : map [string ]stringset {},
235
238
symbols : map [string ]struct {}{},
236
239
postings : index .NewUnorderedMemPostings (),
240
+ deleted : map [uint64 ]int {},
237
241
}
238
242
h .metrics = newHeadMetrics (h , r )
239
243
@@ -557,7 +561,13 @@ func (h *Head) Truncate(mint int64) (err error) {
557
561
}
558
562
559
563
keep := func (id uint64 ) bool {
560
- return h .series .getByID (id ) != nil
564
+ if h .series .getByID (id ) != nil {
565
+ return true
566
+ }
567
+ h .deletedMtx .Lock ()
568
+ _ , ok := h .deleted [id ]
569
+ h .deletedMtx .Unlock ()
570
+ return ok
561
571
}
562
572
h .metrics .checkpointCreationTotal .Inc ()
563
573
if _ , err = Checkpoint (h .wal , first , last , keep , mint ); err != nil {
@@ -570,6 +580,17 @@ func (h *Head) Truncate(mint int64) (err error) {
570
580
// that supersedes them.
571
581
level .Error (h .logger ).Log ("msg" , "truncating segments failed" , "err" , err )
572
582
}
583
+
584
+ // The checkpoint is written and segments before it is truncated, so we no
585
+ // longer need to track deleted series that are before it.
586
+ h .deletedMtx .Lock ()
587
+ for ref , segment := range h .deleted {
588
+ if segment < first {
589
+ delete (h .deleted , ref )
590
+ }
591
+ }
592
+ h .deletedMtx .Unlock ()
593
+
573
594
h .metrics .checkpointDeleteTotal .Inc ()
574
595
if err := DeleteCheckpoints (h .wal .Dir (), last ); err != nil {
575
596
// Leftover old checkpoints do not cause problems down the line beyond
@@ -953,6 +974,21 @@ func (h *Head) gc() {
953
974
// Remove deleted series IDs from the postings lists.
954
975
h .postings .Delete (deleted )
955
976
977
+ if h .wal != nil {
978
+ _ , last , _ := h .wal .Segments ()
979
+ h .deletedMtx .Lock ()
980
+ // Keep series records until we're past segment 'last'
981
+ // because the WAL will still have samples records with
982
+ // this ref ID. If we didn't keep these series records then
983
+ // on start up when we replay the WAL, or any other code
984
+ // that reads the WAL, wouldn't be able to use those
985
+ // samples since we would have no labels for that ref ID.
986
+ for ref := range deleted {
987
+ h .deleted [ref ] = last
988
+ }
989
+ h .deletedMtx .Unlock ()
990
+ }
991
+
956
992
// Rebuild symbols and label value indices from what is left in the postings terms.
957
993
symbols := make (map [string ]struct {}, len (h .symbols ))
958
994
values := make (map [string ]stringset , len (h .values ))
0 commit comments