mirror of https://github.com/grafana/loki
Remove dependency on Bigchunk, which is a leftover of Cortex and is only used in tests (#10354)
**What this PR does / why we need it**: This PR removes the dependency on "Bigchunk", which is a "default" implementation of the `chunk.Data` interface and used only in tests. **Special notes for your reviewer**: The PR replaces the usage of this chunk type with the Loki implementation (`chunkenc.MemChunk` wrapped into `chunkenc.Facade`) where possible. In case where it was not possible (tests in `pkg/storage/chunk` package) due to otherwise circular import, it was replaces by the `chunk.dummyChunk` implementation, which is just a no-op that implements `chunk.Data` interface) The PR also removes the protos for the ingester client (`pkg/ingester/client/ingester.proto`) which were only referenced in the removed `pkg/util/chunkcompat/compat.go` file. Signed-off-by: Christian Haudum <christian.haudum@gmail.com>pull/10394/head
parent
92ba055ae5
commit
31981bd4af
File diff suppressed because it is too large
Load Diff
@ -1,167 +0,0 @@ |
||||
syntax = "proto3"; |
||||
|
||||
package ingesterpb; |
||||
|
||||
import "gogoproto/gogo.proto"; |
||||
import "pkg/logproto/logproto.proto"; |
||||
import "pkg/logproto/metrics.proto"; |
||||
|
||||
option go_package = "github.com/grafana/loki/pkg/ingester/client"; |
||||
option (gogoproto.marshaler_all) = true; |
||||
option (gogoproto.unmarshaler_all) = true; |
||||
|
||||
service Ingester { |
||||
rpc Push(logproto.WriteRequest) returns (logproto.WriteResponse) {} |
||||
|
||||
rpc Query(QueryRequest) returns (QueryResponse) {} |
||||
|
||||
rpc QueryStream(QueryRequest) returns (stream QueryStreamResponse) {} |
||||
|
||||
rpc QueryExemplars(ExemplarQueryRequest) returns (ExemplarQueryResponse) {} |
||||
|
||||
rpc LabelValues(LabelValuesRequest) returns (LabelValuesResponse) {} |
||||
|
||||
rpc LabelNames(LabelNamesRequest) returns (LabelNamesResponse) {} |
||||
|
||||
rpc UserStats(UserStatsRequest) returns (UserStatsResponse) {} |
||||
|
||||
rpc AllUserStats(UserStatsRequest) returns (UsersStatsResponse) {} |
||||
|
||||
rpc MetricsForLabelMatchers(MetricsForLabelMatchersRequest) returns (MetricsForLabelMatchersResponse) {} |
||||
|
||||
rpc MetricsMetadata(MetricsMetadataRequest) returns (MetricsMetadataResponse) {} |
||||
|
||||
// TransferChunks allows leaving ingester (client) to stream chunks directly to joining ingesters (server). |
||||
rpc TransferChunks(stream TimeSeriesChunk) returns (TransferChunksResponse) {} |
||||
} |
||||
|
||||
message ReadRequest { |
||||
repeated QueryRequest queries = 1; |
||||
} |
||||
|
||||
message ReadResponse { |
||||
repeated QueryResponse results = 1; |
||||
} |
||||
|
||||
message QueryRequest { |
||||
int64 start_timestamp_ms = 1; |
||||
int64 end_timestamp_ms = 2; |
||||
repeated LabelMatcher matchers = 3; |
||||
} |
||||
|
||||
message ExemplarQueryRequest { |
||||
int64 start_timestamp_ms = 1; |
||||
int64 end_timestamp_ms = 2; |
||||
repeated LabelMatchers matchers = 3; |
||||
} |
||||
|
||||
message QueryResponse { |
||||
repeated logproto.TimeSeries timeseries = 1 [(gogoproto.nullable) = false]; |
||||
} |
||||
|
||||
// QueryStreamResponse contains a batch of timeseries chunks or timeseries. Only one of these series will be populated. |
||||
message QueryStreamResponse { |
||||
repeated TimeSeriesChunk chunkseries = 1 [(gogoproto.nullable) = false]; |
||||
repeated logproto.TimeSeries timeseries = 2 [(gogoproto.nullable) = false]; |
||||
} |
||||
|
||||
message ExemplarQueryResponse { |
||||
repeated logproto.TimeSeries timeseries = 1 [(gogoproto.nullable) = false]; |
||||
} |
||||
|
||||
message LabelValuesRequest { |
||||
string label_name = 1; |
||||
int64 start_timestamp_ms = 2; |
||||
int64 end_timestamp_ms = 3; |
||||
LabelMatchers matchers = 4; |
||||
} |
||||
|
||||
message LabelValuesResponse { |
||||
repeated string label_values = 1; |
||||
} |
||||
|
||||
message LabelNamesRequest { |
||||
int64 start_timestamp_ms = 1; |
||||
int64 end_timestamp_ms = 2; |
||||
} |
||||
|
||||
message LabelNamesResponse { |
||||
repeated string label_names = 1; |
||||
} |
||||
|
||||
message UserStatsRequest {} |
||||
|
||||
message UserStatsResponse { |
||||
double ingestion_rate = 1; |
||||
uint64 num_series = 2; |
||||
double api_ingestion_rate = 3; |
||||
double rule_ingestion_rate = 4; |
||||
} |
||||
|
||||
message UserIDStatsResponse { |
||||
string user_id = 1; |
||||
UserStatsResponse data = 2; |
||||
} |
||||
|
||||
message UsersStatsResponse { |
||||
repeated UserIDStatsResponse stats = 1; |
||||
} |
||||
|
||||
message MetricsForLabelMatchersRequest { |
||||
int64 start_timestamp_ms = 1; |
||||
int64 end_timestamp_ms = 2; |
||||
repeated LabelMatchers matchers_set = 3; |
||||
} |
||||
|
||||
message MetricsForLabelMatchersResponse { |
||||
repeated logproto.Metric metric = 1; |
||||
} |
||||
|
||||
message MetricsMetadataRequest {} |
||||
|
||||
message MetricsMetadataResponse { |
||||
repeated logproto.MetricMetadata metadata = 1; |
||||
} |
||||
|
||||
message TimeSeriesChunk { |
||||
string from_ingester_id = 1; |
||||
string user_id = 2; |
||||
repeated logproto.LegacyLabelPair labels = 3 [ |
||||
(gogoproto.nullable) = false, |
||||
(gogoproto.customtype) = "github.com/grafana/loki/pkg/logproto.LabelAdapter" |
||||
]; |
||||
repeated Chunk chunks = 4 [(gogoproto.nullable) = false]; |
||||
} |
||||
|
||||
message Chunk { |
||||
int64 start_timestamp_ms = 1; |
||||
int64 end_timestamp_ms = 2; |
||||
int32 encoding = 3; |
||||
bytes data = 4; |
||||
} |
||||
|
||||
message TransferChunksResponse {} |
||||
|
||||
message LabelMatchers { |
||||
repeated LabelMatcher matchers = 1; |
||||
} |
||||
|
||||
enum MatchType { |
||||
EQUAL = 0; |
||||
NOT_EQUAL = 1; |
||||
REGEX_MATCH = 2; |
||||
REGEX_NO_MATCH = 3; |
||||
} |
||||
|
||||
message LabelMatcher { |
||||
MatchType type = 1; |
||||
string name = 2; |
||||
string value = 3; |
||||
} |
||||
|
||||
message TimeSeriesFile { |
||||
string from_ingester_id = 1; |
||||
string user_id = 2; |
||||
string filename = 3; |
||||
bytes data = 4; |
||||
} |
@ -1,256 +0,0 @@ |
||||
package chunk |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/binary" |
||||
"errors" |
||||
"io" |
||||
|
||||
"github.com/prometheus/common/model" |
||||
"github.com/prometheus/prometheus/tsdb/chunkenc" |
||||
|
||||
"github.com/grafana/loki/pkg/util/filter" |
||||
) |
||||
|
||||
const samplesPerChunk = 120 |
||||
|
||||
var errOutOfBounds = errors.New("out of bounds") |
||||
|
||||
type smallChunk struct { |
||||
chunkenc.XORChunk |
||||
start int64 |
||||
} |
||||
|
||||
// bigchunk is a set of prometheus/tsdb chunks. It grows over time and has no
|
||||
// upperbound on number of samples it can contain.
|
||||
type bigchunk struct { |
||||
chunks []smallChunk |
||||
|
||||
appender chunkenc.Appender |
||||
remainingSamples int |
||||
} |
||||
|
||||
func newBigchunk() *bigchunk { |
||||
return &bigchunk{} |
||||
} |
||||
|
||||
// TODO(owen-d): remove bigchunk from our code, we don't use it.
|
||||
// Hack an Entries() impl
|
||||
func (b *bigchunk) Entries() int { return 0 } |
||||
|
||||
func (b *bigchunk) Add(sample model.SamplePair) (Data, error) { |
||||
if b.remainingSamples == 0 { |
||||
if bigchunkSizeCapBytes > 0 && b.Size() > bigchunkSizeCapBytes { |
||||
return addToOverflowChunk(sample) |
||||
} |
||||
if err := b.addNextChunk(sample.Timestamp); err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
b.appender.Append(int64(sample.Timestamp), float64(sample.Value)) |
||||
b.remainingSamples-- |
||||
return nil, nil |
||||
} |
||||
|
||||
// addNextChunk adds a new XOR "subchunk" to the internal list of chunks.
|
||||
func (b *bigchunk) addNextChunk(start model.Time) error { |
||||
// To save memory, we "compact" the previous chunk - the array backing the slice
|
||||
// will be upto 2x too big, and we can save this space.
|
||||
const chunkCapacityExcess = 32 // don't bother copying if it's within this range
|
||||
if l := len(b.chunks); l > 0 { |
||||
oldBuf := b.chunks[l-1].XORChunk.Bytes() |
||||
if cap(oldBuf) > len(oldBuf)+chunkCapacityExcess { |
||||
buf := make([]byte, len(oldBuf)) |
||||
copy(buf, oldBuf) |
||||
compacted, err := chunkenc.FromData(chunkenc.EncXOR, buf) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
b.chunks[l-1].XORChunk = *compacted.(*chunkenc.XORChunk) |
||||
} |
||||
} |
||||
|
||||
// Explicitly reallocate slice to avoid up to 2x overhead if we let append() do it
|
||||
if len(b.chunks)+1 > cap(b.chunks) { |
||||
newChunks := make([]smallChunk, len(b.chunks), len(b.chunks)+1) |
||||
copy(newChunks, b.chunks) |
||||
b.chunks = newChunks |
||||
} |
||||
b.chunks = append(b.chunks, smallChunk{ |
||||
XORChunk: *chunkenc.NewXORChunk(), |
||||
start: int64(start), |
||||
}) |
||||
|
||||
appender, err := b.chunks[len(b.chunks)-1].Appender() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
b.appender = appender |
||||
b.remainingSamples = samplesPerChunk |
||||
return nil |
||||
} |
||||
|
||||
func (b *bigchunk) Rebound(_, _ model.Time, _ filter.Func) (Data, error) { |
||||
return nil, errors.New("not implemented") |
||||
} |
||||
|
||||
func (b *bigchunk) Marshal(wio io.Writer) error { |
||||
w := writer{wio} |
||||
if err := w.WriteVarInt16(uint16(len(b.chunks))); err != nil { |
||||
return err |
||||
} |
||||
for _, chunk := range b.chunks { |
||||
buf := chunk.Bytes() |
||||
if err := w.WriteVarInt16(uint16(len(buf))); err != nil { |
||||
return err |
||||
} |
||||
if _, err := w.Write(buf); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (b *bigchunk) MarshalToBuf(buf []byte) error { |
||||
writer := bytes.NewBuffer(buf) |
||||
return b.Marshal(writer) |
||||
} |
||||
|
||||
func (b *bigchunk) UnmarshalFromBuf(buf []byte) error { |
||||
r := reader{buf: buf} |
||||
numChunks, err := r.ReadUint16() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
b.chunks = make([]smallChunk, 0, numChunks+1) // allow one extra space in case we want to add new data
|
||||
var reuseIter chunkenc.Iterator |
||||
for i := uint16(0); i < numChunks; i++ { |
||||
chunkLen, err := r.ReadUint16() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
chunkBuf, err := r.ReadBytes(int(chunkLen)) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
chunk, err := chunkenc.FromData(chunkenc.EncXOR, chunkBuf) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
var start int64 |
||||
start, reuseIter, err = firstTime(chunk, reuseIter) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
b.chunks = append(b.chunks, smallChunk{ |
||||
XORChunk: *chunk.(*chunkenc.XORChunk), |
||||
start: start, |
||||
}) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (b *bigchunk) Encoding() Encoding { |
||||
return Bigchunk |
||||
} |
||||
|
||||
func (b *bigchunk) Utilization() float64 { |
||||
return 1.0 |
||||
} |
||||
|
||||
func (b *bigchunk) Len() int { |
||||
sum := 0 |
||||
for _, c := range b.chunks { |
||||
sum += c.NumSamples() |
||||
} |
||||
return sum |
||||
} |
||||
|
||||
// Unused, but for compatibility
|
||||
func (b *bigchunk) UncompressedSize() int { return b.Size() } |
||||
|
||||
func (b *bigchunk) Size() int { |
||||
sum := 2 // For the number of sub chunks.
|
||||
for _, c := range b.chunks { |
||||
sum += 2 // For the length of the sub chunk.
|
||||
sum += len(c.Bytes()) |
||||
} |
||||
return sum |
||||
} |
||||
|
||||
func (b *bigchunk) Slice(start, end model.Time) Data { |
||||
i, j := 0, len(b.chunks) |
||||
for k := 0; k < len(b.chunks); k++ { |
||||
if b.chunks[k].start <= int64(start) { |
||||
i = k |
||||
} |
||||
if b.chunks[k].start > int64(end) { |
||||
j = k |
||||
break |
||||
} |
||||
} |
||||
return &bigchunk{ |
||||
chunks: b.chunks[i:j], |
||||
} |
||||
} |
||||
|
||||
type writer struct { |
||||
io.Writer |
||||
} |
||||
|
||||
func (w writer) WriteVarInt16(i uint16) error { |
||||
var b [2]byte |
||||
binary.LittleEndian.PutUint16(b[:], i) |
||||
_, err := w.Write(b[:]) |
||||
return err |
||||
} |
||||
|
||||
type reader struct { |
||||
i int |
||||
buf []byte |
||||
} |
||||
|
||||
func (r *reader) ReadUint16() (uint16, error) { |
||||
if r.i+2 > len(r.buf) { |
||||
return 0, errOutOfBounds |
||||
} |
||||
result := binary.LittleEndian.Uint16(r.buf[r.i:]) |
||||
r.i += 2 |
||||
return result, nil |
||||
} |
||||
|
||||
func (r *reader) ReadBytes(count int) ([]byte, error) { |
||||
if r.i+count > len(r.buf) { |
||||
return nil, errOutOfBounds |
||||
} |
||||
result := r.buf[r.i : r.i+count] |
||||
r.i += count |
||||
return result, nil |
||||
} |
||||
|
||||
// addToOverflowChunk is a utility function that creates a new chunk as overflow
|
||||
// chunk, adds the provided sample to it, and returns a chunk slice containing
|
||||
// the provided old chunk followed by the new overflow chunk.
|
||||
func addToOverflowChunk(s model.SamplePair) (Data, error) { |
||||
overflowChunk := New() |
||||
_, err := overflowChunk.(*bigchunk).Add(s) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return overflowChunk, nil |
||||
} |
||||
|
||||
func firstTime(c chunkenc.Chunk, iter chunkenc.Iterator) (int64, chunkenc.Iterator, error) { |
||||
var first int64 |
||||
iter = c.Iterator(iter) |
||||
if iter.Next() != chunkenc.ValNone { |
||||
first, _ = iter.At() |
||||
} |
||||
return first, iter, iter.Err() |
||||
} |
@ -0,0 +1,54 @@ |
||||
package chunk |
||||
|
||||
import ( |
||||
"io" |
||||
|
||||
"github.com/prometheus/common/model" |
||||
|
||||
"github.com/grafana/loki/pkg/util/filter" |
||||
) |
||||
|
||||
func newDummyChunk() *dummyChunk { |
||||
return &dummyChunk{} |
||||
} |
||||
|
||||
// dummyChunk implements chunk.Data
|
||||
// It is a placeholder chunk with Encoding(0)
|
||||
// It can be used in tests where the content of a chunk is irrelevant.
|
||||
type dummyChunk struct{} |
||||
|
||||
func (chk *dummyChunk) Add(sample model.SamplePair) (Data, error) { |
||||
return nil, nil |
||||
} |
||||
|
||||
func (chk *dummyChunk) Marshal(io.Writer) error { |
||||
return nil |
||||
} |
||||
|
||||
func (chk *dummyChunk) UnmarshalFromBuf([]byte) error { |
||||
return nil |
||||
} |
||||
|
||||
func (chk *dummyChunk) Encoding() Encoding { |
||||
return Dummy |
||||
} |
||||
|
||||
func (chk *dummyChunk) Rebound(start, end model.Time, filter filter.Func) (Data, error) { |
||||
return nil, nil |
||||
} |
||||
|
||||
func (chk *dummyChunk) Size() int { |
||||
return 0 |
||||
} |
||||
|
||||
func (chk *dummyChunk) UncompressedSize() int { |
||||
return 0 |
||||
} |
||||
|
||||
func (chk *dummyChunk) Entries() int { |
||||
return 0 |
||||
} |
||||
|
||||
func (chk *dummyChunk) Utilization() float64 { |
||||
return 0 |
||||
} |
@ -1,53 +0,0 @@ |
||||
package chunkcompat |
||||
|
||||
import ( |
||||
"bytes" |
||||
|
||||
"github.com/prometheus/common/model" |
||||
"github.com/prometheus/prometheus/model/labels" |
||||
|
||||
"github.com/grafana/loki/pkg/ingester/client" |
||||
"github.com/grafana/loki/pkg/storage/chunk" |
||||
) |
||||
|
||||
// FromChunks converts []client.Chunk to []chunk.Chunk.
|
||||
func FromChunks(userID string, metric labels.Labels, in []client.Chunk) ([]chunk.Chunk, error) { |
||||
out := make([]chunk.Chunk, 0, len(in)) |
||||
for _, i := range in { |
||||
o, err := chunk.NewForEncoding(chunk.Encoding(byte(i.Encoding))) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if err := o.UnmarshalFromBuf(i.Data); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
firstTime, lastTime := model.Time(i.StartTimestampMs), model.Time(i.EndTimestampMs) |
||||
// As the lifetime of this chunk is scopes to this request, we don't need
|
||||
// to supply a fingerprint.
|
||||
out = append(out, chunk.NewChunk(userID, 0, metric, o, firstTime, lastTime)) |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
// ToChunks converts []chunk.Chunk to []client.Chunk.
|
||||
func ToChunks(in []chunk.Chunk) ([]client.Chunk, error) { |
||||
out := make([]client.Chunk, 0, len(in)) |
||||
for _, i := range in { |
||||
wireChunk := client.Chunk{ |
||||
StartTimestampMs: int64(i.From), |
||||
EndTimestampMs: int64(i.Through), |
||||
Encoding: int32(i.Data.Encoding()), |
||||
} |
||||
|
||||
buf := bytes.NewBuffer(make([]byte, 0, 1024)) |
||||
if err := i.Data.Marshal(buf); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
wireChunk.Data = buf.Bytes() |
||||
out = append(out, wireChunk) |
||||
} |
||||
return out, nil |
||||
} |
Loading…
Reference in new issue