github.com/thanos-io/thanos@v0.32.5/pkg/block/metadata/markers.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package metadata 5 6 import ( 7 "context" 8 "encoding/json" 9 "io" 10 "path" 11 12 "github.com/go-kit/log" 13 "github.com/oklog/ulid" 14 "github.com/pkg/errors" 15 "github.com/thanos-io/objstore" 16 17 "github.com/thanos-io/thanos/pkg/runutil" 18 ) 19 20 const ( 21 // DeletionMarkFilename is the known json filename for optional file storing details about when block is marked for deletion. 22 // If such file is present in block dir, it means the block is meant to be deleted after certain delay. 23 DeletionMarkFilename = "deletion-mark.json" 24 // NoCompactMarkFilename is the known json filename for optional file storing details about why block has to be excluded from compaction. 25 // If such file is present in block dir, it means the block has to excluded from compaction (both vertical and horizontal) or rewrite (e.g deletions). 26 NoCompactMarkFilename = "no-compact-mark.json" 27 // NoDownsampleMarkFilename is the known json filenanme for optional file storing details about why block has to be excluded from downsampling. 28 // If such file is present in block dir, it means the block has to be excluded from downsampling. 29 NoDownsampleMarkFilename = "no-downsample-mark.json" 30 // DeletionMarkVersion1 is the version of deletion-mark file supported by Thanos. 31 DeletionMarkVersion1 = 1 32 // NoCompactMarkVersion1 is the version of no-compact-mark file supported by Thanos. 33 NoCompactMarkVersion1 = 1 34 // NoDownsampleVersion1 is the version of no-downsample-mark file supported by Thanos. 35 NoDownsampleMarkVersion1 = 1 36 ) 37 38 var ( 39 // ErrorMarkerNotFound is the error when marker file is not found. 40 ErrorMarkerNotFound = errors.New("marker not found") 41 // ErrorUnmarshalMarker is the error when unmarshalling marker JSON file. 42 // This error can occur because marker has been partially uploaded to block storage 43 // or the marker file is not a valid json file. 44 ErrorUnmarshalMarker = errors.New("unmarshal marker JSON") 45 ) 46 47 type Marker interface { 48 markerFilename() string 49 } 50 51 // DeletionMark stores block id and when block was marked for deletion. 52 type DeletionMark struct { 53 // ID of the tsdb block. 54 ID ulid.ULID `json:"id"` 55 // Version of the file. 56 Version int `json:"version"` 57 // Details is a human readable string giving details of reason. 58 Details string `json:"details,omitempty"` 59 60 // DeletionTime is a unix timestamp of when the block was marked to be deleted. 61 DeletionTime int64 `json:"deletion_time"` 62 } 63 64 func (m *DeletionMark) markerFilename() string { return DeletionMarkFilename } 65 66 // NoCompactReason is a reason for a block to be excluded from compaction. 67 type NoCompactReason string 68 69 // NoDownsampleReason is a reason for a block to be excluded from downsample. 70 type NoDownsampleReason string 71 72 const ( 73 // ManualNoCompactReason is a custom reason of excluding from compaction that should be added when no-compact mark is added for unknown/user specified reason. 74 ManualNoCompactReason NoCompactReason = "manual" 75 // ManualNoDownsampleReason is a custom reason of excluding from downsample that should be added when no-downsample mark is added for unknown/user specified reason. 76 ManualNoDownsampleReason NoDownsampleReason = "manual" 77 // IndexSizeExceedingNoCompactReason is a reason of index being too big (for example exceeding 64GB limit: https://github.com/thanos-io/thanos/issues/1424) 78 // This reason can be ignored when vertical block sharding will be implemented. 79 IndexSizeExceedingNoCompactReason = "index-size-exceeding" 80 // OutOfOrderChunksNoCompactReason is a reason of to no compact block with index contains out of order chunk so that the compaction is not blocked. 81 OutOfOrderChunksNoCompactReason = "block-index-out-of-order-chunk" 82 ) 83 84 // NoCompactMark marker stores reason of block being excluded from compaction if needed. 85 type NoCompactMark struct { 86 // ID of the tsdb block. 87 ID ulid.ULID `json:"id"` 88 // Version of the file. 89 Version int `json:"version"` 90 // Details is a human readable string giving details of reason. 91 Details string `json:"details,omitempty"` 92 93 // NoCompactTime is a unix timestamp of when the block was marked for no compact. 94 NoCompactTime int64 `json:"no_compact_time"` 95 Reason NoCompactReason `json:"reason"` 96 } 97 98 func (n *NoCompactMark) markerFilename() string { return NoCompactMarkFilename } 99 100 // NoDownsampleMark marker stores reason of block being excluded from downsample if needed. 101 type NoDownsampleMark struct { 102 // ID of the tsdb block. 103 ID ulid.ULID `json:"id"` 104 // Version of the file. 105 Version int `json:"version"` 106 // Details is a human readable string giving details of reason. 107 Details string `json:"details,omitempty"` 108 109 // NoDownsampleTime is a unix timestamp of when the block was marked for no downsample. 110 NoDownsampleTime int64 `json:"no_downsample_time"` 111 Reason NoDownsampleReason `json:"reason"` 112 } 113 114 func (n *NoDownsampleMark) markerFilename() string { return NoDownsampleMarkFilename } 115 116 // ReadMarker reads the given mark file from <dir>/<marker filename>.json in bucket. 117 func ReadMarker(ctx context.Context, logger log.Logger, bkt objstore.InstrumentedBucketReader, dir string, marker Marker) error { 118 markerFile := path.Join(dir, marker.markerFilename()) 119 r, err := bkt.ReaderWithExpectedErrs(bkt.IsObjNotFoundErr).Get(ctx, markerFile) 120 if err != nil { 121 if bkt.IsObjNotFoundErr(err) { 122 return ErrorMarkerNotFound 123 } 124 return errors.Wrapf(err, "get file: %s", markerFile) 125 } 126 defer runutil.CloseWithLogOnErr(logger, r, "close bkt marker reader") 127 128 metaContent, err := io.ReadAll(r) 129 if err != nil { 130 return errors.Wrapf(err, "read file: %s", markerFile) 131 } 132 133 if err := json.Unmarshal(metaContent, marker); err != nil { 134 return errors.Wrapf(ErrorUnmarshalMarker, "file: %s; err: %v", markerFile, err.Error()) 135 } 136 switch marker.markerFilename() { 137 case NoCompactMarkFilename: 138 if version := marker.(*NoCompactMark).Version; version != NoCompactMarkVersion1 { 139 return errors.Errorf("unexpected no-compact-mark file version %d, expected %d", version, NoCompactMarkVersion1) 140 } 141 case NoDownsampleMarkFilename: 142 if version := marker.(*NoDownsampleMark).Version; version != NoDownsampleMarkVersion1 { 143 return errors.Errorf("unexpected no-downsample-mark file version %d, expected %d", version, NoDownsampleMarkVersion1) 144 } 145 case DeletionMarkFilename: 146 if version := marker.(*DeletionMark).Version; version != DeletionMarkVersion1 { 147 return errors.Errorf("unexpected deletion-mark file version %d, expected %d", version, DeletionMarkVersion1) 148 } 149 } 150 return nil 151 }