2019-05-22 21:23:23 +00:00
package transport
import (
2020-08-10 10:17:12 +00:00
"errors"
2019-05-22 21:23:23 +00:00
"flag"
"fmt"
"io"
"net"
2020-06-30 21:58:26 +00:00
"net/http"
2019-05-22 21:23:23 +00:00
"sync"
"sync/atomic"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/encoding"
2020-05-15 12:42:30 +00:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime"
2019-05-22 21:23:23 +00:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/handshake"
2020-06-30 21:58:26 +00:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/httpserver"
2021-05-08 16:36:00 +00:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/ingestserver"
2019-05-22 21:23:23 +00:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/netutil"
2021-05-08 14:55:44 +00:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/clusternative"
2022-05-31 23:31:40 +00:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/querytracer"
2019-05-22 21:23:23 +00:00
"github.com/VictoriaMetrics/VictoriaMetrics/lib/storage"
"github.com/VictoriaMetrics/metrics"
)
var (
2020-09-10 21:29:26 +00:00
maxTagKeysPerSearch = flag . Int ( "search.maxTagKeys" , 100e3 , "The maximum number of tag keys returned per search" )
maxTagValuesPerSearch = flag . Int ( "search.maxTagValues" , 100e3 , "The maximum number of tag values returned per search" )
maxTagValueSuffixesPerSearch = flag . Int ( "search.maxTagValueSuffixesPerSearch" , 100e3 , "The maximum number of tag value suffixes returned from /metrics/find" )
2022-03-26 08:17:37 +00:00
maxMetricsPerSearch = flag . Int ( "search.maxUniqueTimeseries" , 0 , "The maximum number of unique time series, which can be scanned during every query. This allows protecting against heavy queries, which select unexpectedly high number of series. Zero means 'no limit'. See also -search.max* command-line flags at vmselect" )
2019-05-22 21:23:23 +00:00
2019-06-10 11:52:41 +00:00
precisionBits = flag . Int ( "precisionBits" , 64 , "The number of precision bits to store per each value. Lower precision bits improves data compression at the cost of precision loss" )
2022-05-06 13:24:45 +00:00
disableRPCCompression = flag . Bool ( ` rpc.disableCompression ` , false , "Whether to disable compression of the data sent from vmstorage to vmselect. This reduces CPU usage at the cost of higher network bandwidth usage" )
2020-06-30 21:58:26 +00:00
denyQueriesOutsideRetention = flag . Bool ( "denyQueriesOutsideRetention" , false , "Whether to deny queries outside of the configured -retentionPeriod. " +
"When set, then /api/v1/query_range would return '503 Service Unavailable' error for queries with 'from' value outside -retentionPeriod. " +
"This may be useful when multiple data sources with distinct retentions are hidden behind query-tee" )
2019-05-22 21:23:23 +00:00
)
// Server processes connections from vminsert and vmselect.
type Server struct {
2020-05-12 17:20:57 +00:00
// Move stopFlag to the top of the struct in order to fix atomic access to it on 32-bit arches.
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/212
stopFlag uint64
2019-05-22 21:23:23 +00:00
storage * storage . Storage
vminsertLN net . Listener
vmselectLN net . Listener
vminsertWG sync . WaitGroup
vmselectWG sync . WaitGroup
2021-05-08 16:36:00 +00:00
vminsertConnsMap ingestserver . ConnsMap
vmselectConnsMap ingestserver . ConnsMap
2019-05-22 21:23:23 +00:00
}
// NewServer returns new Server.
func NewServer ( vminsertAddr , vmselectAddr string , storage * storage . Storage ) ( * Server , error ) {
2022-03-17 17:42:10 +00:00
vminsertLN , err := netutil . NewTCPListener ( "vminsert" , vminsertAddr , nil )
2019-05-22 21:23:23 +00:00
if err != nil {
2020-06-30 19:58:18 +00:00
return nil , fmt . Errorf ( "unable to listen vminsertAddr %s: %w" , vminsertAddr , err )
2019-05-22 21:23:23 +00:00
}
2022-03-17 17:42:10 +00:00
vmselectLN , err := netutil . NewTCPListener ( "vmselect" , vmselectAddr , nil )
2019-05-22 21:23:23 +00:00
if err != nil {
2020-06-30 19:58:18 +00:00
return nil , fmt . Errorf ( "unable to listen vmselectAddr %s: %w" , vmselectAddr , err )
2019-05-22 21:23:23 +00:00
}
if err := encoding . CheckPrecisionBits ( uint8 ( * precisionBits ) ) ; err != nil {
2020-06-30 19:58:18 +00:00
return nil , fmt . Errorf ( "invalid -precisionBits: %w" , err )
2019-05-22 21:23:23 +00:00
}
s := & Server {
storage : storage ,
vminsertLN : vminsertLN ,
vmselectLN : vmselectLN ,
}
s . vminsertConnsMap . Init ( )
s . vmselectConnsMap . Init ( )
return s , nil
}
// RunVMInsert runs a server accepting connections from vminsert.
func ( s * Server ) RunVMInsert ( ) {
logger . Infof ( "accepting vminsert conns at %s" , s . vminsertLN . Addr ( ) )
for {
c , err := s . vminsertLN . Accept ( )
if err != nil {
if pe , ok := err . ( net . Error ) ; ok && pe . Temporary ( ) {
continue
}
if s . isStopping ( ) {
return
}
logger . Panicf ( "FATAL: cannot process vminsert conns at %s: %s" , s . vminsertLN . Addr ( ) , err )
}
logger . Infof ( "accepted vminsert conn from %s" , c . RemoteAddr ( ) )
2020-06-05 08:50:11 +00:00
if ! s . vminsertConnsMap . Add ( c ) {
// The server is closed.
_ = c . Close ( )
return
}
2019-05-22 21:23:23 +00:00
vminsertConns . Inc ( )
s . vminsertWG . Add ( 1 )
go func ( ) {
defer func ( ) {
s . vminsertConnsMap . Delete ( c )
vminsertConns . Dec ( )
s . vminsertWG . Done ( )
} ( )
// There is no need in response compression, since
2020-05-21 11:04:45 +00:00
// vmstorage sends only small packets to vminsert.
2019-05-22 21:23:23 +00:00
compressionLevel := 0
bc , err := handshake . VMInsertServer ( c , compressionLevel )
if err != nil {
if s . isStopping ( ) {
// c is stopped inside Server.MustClose
return
}
logger . Errorf ( "cannot perform vminsert handshake with client %q: %s" , c . RemoteAddr ( ) , err )
_ = c . Close ( )
return
}
defer func ( ) {
if ! s . isStopping ( ) {
logger . Infof ( "closing vminsert conn from %s" , c . RemoteAddr ( ) )
}
_ = bc . Close ( )
} ( )
logger . Infof ( "processing vminsert conn from %s" , c . RemoteAddr ( ) )
if err := s . processVMInsertConn ( bc ) ; err != nil {
if s . isStopping ( ) {
return
}
vminsertConnErrors . Inc ( )
logger . Errorf ( "cannot process vminsert conn from %s: %s" , c . RemoteAddr ( ) , err )
}
} ( )
}
}
var (
vminsertConns = metrics . NewCounter ( "vm_vminsert_conns" )
vminsertConnErrors = metrics . NewCounter ( "vm_vminsert_conn_errors_total" )
)
// RunVMSelect runs a server accepting connections from vmselect.
func ( s * Server ) RunVMSelect ( ) {
logger . Infof ( "accepting vmselect conns at %s" , s . vmselectLN . Addr ( ) )
for {
c , err := s . vmselectLN . Accept ( )
if err != nil {
if pe , ok := err . ( net . Error ) ; ok && pe . Temporary ( ) {
continue
}
if s . isStopping ( ) {
return
}
logger . Panicf ( "FATAL: cannot process vmselect conns at %s: %s" , s . vmselectLN . Addr ( ) , err )
}
logger . Infof ( "accepted vmselect conn from %s" , c . RemoteAddr ( ) )
2020-06-05 08:50:11 +00:00
if ! s . vmselectConnsMap . Add ( c ) {
// The server is closed.
_ = c . Close ( )
return
}
2019-05-22 21:23:23 +00:00
vmselectConns . Inc ( )
s . vmselectWG . Add ( 1 )
go func ( ) {
defer func ( ) {
s . vmselectConnsMap . Delete ( c )
vmselectConns . Dec ( )
s . vmselectWG . Done ( )
} ( )
2019-06-10 11:52:41 +00:00
// Compress responses to vmselect even if they already contain compressed blocks.
// Responses contain uncompressed metric names, which should compress well
// when the response contains high number of time series.
// Additionally, recently added metric blocks are usually uncompressed, so the compression
// should save network bandwidth.
compressionLevel := 1
if * disableRPCCompression {
compressionLevel = 0
}
2019-05-22 21:23:23 +00:00
bc , err := handshake . VMSelectServer ( c , compressionLevel )
if err != nil {
if s . isStopping ( ) {
// c is closed inside Server.MustClose
return
}
logger . Errorf ( "cannot perform vmselect handshake with client %q: %s" , c . RemoteAddr ( ) , err )
_ = c . Close ( )
return
}
defer func ( ) {
if ! s . isStopping ( ) {
logger . Infof ( "closing vmselect conn from %s" , c . RemoteAddr ( ) )
}
_ = bc . Close ( )
} ( )
logger . Infof ( "processing vmselect conn from %s" , c . RemoteAddr ( ) )
if err := s . processVMSelectConn ( bc ) ; err != nil {
if s . isStopping ( ) {
return
}
vmselectConnErrors . Inc ( )
logger . Errorf ( "cannot process vmselect conn %s: %s" , c . RemoteAddr ( ) , err )
}
} ( )
}
}
var (
vmselectConns = metrics . NewCounter ( "vm_vmselect_conns" )
vmselectConnErrors = metrics . NewCounter ( "vm_vmselect_conn_errors_total" )
)
// MustClose gracefully closes the server,
// so it no longer touches s.storage after returning.
func ( s * Server ) MustClose ( ) {
// Mark the server as stoping.
s . setIsStopping ( )
// Stop accepting new connections from vminsert and vmselect.
if err := s . vminsertLN . Close ( ) ; err != nil {
logger . Panicf ( "FATAL: cannot close vminsert listener: %s" , err )
}
if err := s . vmselectLN . Close ( ) ; err != nil {
logger . Panicf ( "FATAL: cannot close vmselect listener: %s" , err )
}
// Close existing connections from vminsert, so the goroutines
// processing these connections are finished.
s . vminsertConnsMap . CloseAll ( )
// Close existing connections from vmselect, so the goroutines
// processing these connections are finished.
s . vmselectConnsMap . CloseAll ( )
// Wait until all the goroutines processing vminsert and vmselect conns
// are finished.
s . vminsertWG . Wait ( )
s . vmselectWG . Wait ( )
}
func ( s * Server ) setIsStopping ( ) {
atomic . StoreUint64 ( & s . stopFlag , 1 )
}
func ( s * Server ) isStopping ( ) bool {
return atomic . LoadUint64 ( & s . stopFlag ) != 0
}
2020-04-27 06:32:08 +00:00
func ( s * Server ) processVMInsertConn ( bc * handshake . BufferedConn ) error {
2021-05-08 14:55:44 +00:00
return clusternative . ParseStream ( bc , func ( rows [ ] storage . MetricRow ) error {
vminsertMetricsRead . Add ( len ( rows ) )
return s . storage . AddRows ( rows , uint8 ( * precisionBits ) )
2021-10-08 09:52:56 +00:00
} , s . storage . IsReadOnly )
2020-09-28 18:37:58 +00:00
}
2021-05-08 14:55:44 +00:00
var vminsertMetricsRead = metrics . NewCounter ( "vm_vminsert_metrics_read_total" )
2020-09-28 18:37:58 +00:00
2019-05-22 21:23:23 +00:00
func ( s * Server ) processVMSelectConn ( bc * handshake . BufferedConn ) error {
ctx := & vmselectRequestCtx {
bc : bc ,
sizeBuf : make ( [ ] byte , 8 ) ,
}
for {
2019-12-02 18:44:18 +00:00
if err := s . processVMSelectRequest ( ctx ) ; err != nil {
2019-05-22 21:23:23 +00:00
if err == io . EOF {
// Remote client gracefully closed the connection.
return nil
}
2020-08-10 10:17:12 +00:00
if errors . Is ( err , storage . ErrDeadlineExceeded ) {
return fmt . Errorf ( "cannot process vmselect request in %d seconds: %w" , ctx . timeout , err )
}
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot process vmselect request: %w" , err )
2019-05-22 21:23:23 +00:00
}
if err := bc . Flush ( ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot flush compressed buffers: %w" , err )
2019-05-22 21:23:23 +00:00
}
}
}
type vmselectRequestCtx struct {
bc * handshake . BufferedConn
sizeBuf [ ] byte
dataBuf [ ] byte
2022-05-31 23:31:40 +00:00
qt * querytracer . Tracer
2019-05-22 21:23:23 +00:00
sq storage . SearchQuery
tfss [ ] * storage . TagFilters
sr storage . Search
2020-04-27 05:13:41 +00:00
mb storage . MetricBlock
2020-07-23 17:42:57 +00:00
2020-08-10 10:17:12 +00:00
// timeout in seconds for the current request
timeout uint64
2020-07-23 17:42:57 +00:00
// deadline in unix timestamp seconds for the current request.
deadline uint64
2019-05-22 21:23:23 +00:00
}
2020-11-04 22:15:43 +00:00
func ( ctx * vmselectRequestCtx ) readTimeRange ( ) ( storage . TimeRange , error ) {
var tr storage . TimeRange
minTimestamp , err := ctx . readUint64 ( )
if err != nil {
return tr , fmt . Errorf ( "cannot read minTimestamp: %w" , err )
}
maxTimestamp , err := ctx . readUint64 ( )
if err != nil {
return tr , fmt . Errorf ( "cannot read maxTimestamp: %w" , err )
}
tr . MinTimestamp = int64 ( minTimestamp )
tr . MaxTimestamp = int64 ( maxTimestamp )
return tr , nil
}
2022-06-10 06:50:30 +00:00
func ( ctx * vmselectRequestCtx ) readLimit ( ) ( int , error ) {
n , err := ctx . readUint32 ( )
if err != nil {
return 0 , fmt . Errorf ( "cannot read limit: %w" , err )
}
if n > 1 << 31 - 1 {
n = 1 << 31 - 1
}
return int ( n ) , nil
}
2019-05-22 21:23:23 +00:00
func ( ctx * vmselectRequestCtx ) readUint32 ( ) ( uint32 , error ) {
2022-02-01 15:48:25 +00:00
ctx . sizeBuf = bytesutil . ResizeNoCopyMayOverallocate ( ctx . sizeBuf , 4 )
2019-05-22 21:23:23 +00:00
if _ , err := io . ReadFull ( ctx . bc , ctx . sizeBuf ) ; err != nil {
if err == io . EOF {
return 0 , err
}
2020-06-30 19:58:18 +00:00
return 0 , fmt . Errorf ( "cannot read uint32: %w" , err )
2019-05-22 21:23:23 +00:00
}
n := encoding . UnmarshalUint32 ( ctx . sizeBuf )
return n , nil
}
2020-09-10 21:29:26 +00:00
func ( ctx * vmselectRequestCtx ) readUint64 ( ) ( uint64 , error ) {
2022-02-01 15:48:25 +00:00
ctx . sizeBuf = bytesutil . ResizeNoCopyMayOverallocate ( ctx . sizeBuf , 8 )
2020-09-10 21:29:26 +00:00
if _ , err := io . ReadFull ( ctx . bc , ctx . sizeBuf ) ; err != nil {
if err == io . EOF {
return 0 , err
}
return 0 , fmt . Errorf ( "cannot read uint64: %w" , err )
}
n := encoding . UnmarshalUint64 ( ctx . sizeBuf )
return n , nil
}
func ( ctx * vmselectRequestCtx ) readAccountIDProjectID ( ) ( uint32 , uint32 , error ) {
accountID , err := ctx . readUint32 ( )
if err != nil {
return 0 , 0 , fmt . Errorf ( "cannot read accountID: %w" , err )
}
projectID , err := ctx . readUint32 ( )
if err != nil {
return 0 , 0 , fmt . Errorf ( "cannot read projectID: %w" , err )
}
return accountID , projectID , nil
}
2020-11-16 08:55:55 +00:00
func ( ctx * vmselectRequestCtx ) readSearchQuery ( ) error {
if err := ctx . readDataBufBytes ( maxSearchQuerySize ) ; err != nil {
return fmt . Errorf ( "cannot read searchQuery: %w" , err )
}
tail , err := ctx . sq . Unmarshal ( ctx . dataBuf )
if err != nil {
return fmt . Errorf ( "cannot unmarshal SearchQuery: %w" , err )
}
if len ( tail ) > 0 {
return fmt . Errorf ( "unexpected non-zero tail left after unmarshaling SearchQuery: (len=%d) %q" , len ( tail ) , tail )
}
return nil
}
2019-05-22 21:23:23 +00:00
func ( ctx * vmselectRequestCtx ) readDataBufBytes ( maxDataSize int ) error {
2022-02-01 15:48:25 +00:00
ctx . sizeBuf = bytesutil . ResizeNoCopyMayOverallocate ( ctx . sizeBuf , 8 )
2019-05-22 21:23:23 +00:00
if _ , err := io . ReadFull ( ctx . bc , ctx . sizeBuf ) ; err != nil {
if err == io . EOF {
return err
}
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot read data size: %w" , err )
2019-05-22 21:23:23 +00:00
}
dataSize := encoding . UnmarshalUint64 ( ctx . sizeBuf )
if dataSize > uint64 ( maxDataSize ) {
return fmt . Errorf ( "too big data size: %d; it mustn't exceed %d bytes" , dataSize , maxDataSize )
}
2022-02-01 15:48:25 +00:00
ctx . dataBuf = bytesutil . ResizeNoCopyMayOverallocate ( ctx . dataBuf , int ( dataSize ) )
2019-05-22 21:23:23 +00:00
if dataSize == 0 {
return nil
}
2019-09-11 11:11:37 +00:00
if n , err := io . ReadFull ( ctx . bc , ctx . dataBuf ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot read data with size %d: %w; read only %d bytes" , dataSize , err , n )
2019-05-22 21:23:23 +00:00
}
return nil
}
2019-08-04 19:15:33 +00:00
func ( ctx * vmselectRequestCtx ) readBool ( ) ( bool , error ) {
2022-02-01 15:48:25 +00:00
ctx . dataBuf = bytesutil . ResizeNoCopyMayOverallocate ( ctx . dataBuf , 1 )
2019-08-04 19:15:33 +00:00
if _ , err := io . ReadFull ( ctx . bc , ctx . dataBuf ) ; err != nil {
if err == io . EOF {
return false , err
}
2020-06-30 19:58:18 +00:00
return false , fmt . Errorf ( "cannot read bool: %w" , err )
2019-08-04 19:15:33 +00:00
}
v := ctx . dataBuf [ 0 ] != 0
return v , nil
}
2020-09-10 21:29:26 +00:00
func ( ctx * vmselectRequestCtx ) readByte ( ) ( byte , error ) {
2022-02-01 15:48:25 +00:00
ctx . dataBuf = bytesutil . ResizeNoCopyMayOverallocate ( ctx . dataBuf , 1 )
2020-09-10 21:29:26 +00:00
if _ , err := io . ReadFull ( ctx . bc , ctx . dataBuf ) ; err != nil {
if err == io . EOF {
return 0 , err
}
return 0 , fmt . Errorf ( "cannot read byte: %w" , err )
}
b := ctx . dataBuf [ 0 ]
return b , nil
}
2019-05-22 21:23:23 +00:00
func ( ctx * vmselectRequestCtx ) writeDataBufBytes ( ) error {
if err := ctx . writeUint64 ( uint64 ( len ( ctx . dataBuf ) ) ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot write data size: %w" , err )
2019-05-22 21:23:23 +00:00
}
if len ( ctx . dataBuf ) == 0 {
return nil
}
if _ , err := ctx . bc . Write ( ctx . dataBuf ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot write data with size %d: %w" , len ( ctx . dataBuf ) , err )
2019-05-22 21:23:23 +00:00
}
return nil
}
2020-02-13 15:32:54 +00:00
// maxErrorMessageSize is the maximum size of error message to send to clients.
const maxErrorMessageSize = 64 * 1024
func ( ctx * vmselectRequestCtx ) writeErrorMessage ( err error ) error {
2020-08-10 10:17:12 +00:00
if errors . Is ( err , storage . ErrDeadlineExceeded ) {
err = fmt . Errorf ( "cannot execute request in %d seconds: %w" , ctx . timeout , err )
}
2020-02-13 15:32:54 +00:00
errMsg := err . Error ( )
if len ( errMsg ) > maxErrorMessageSize {
// Trim too long error message.
errMsg = errMsg [ : maxErrorMessageSize ]
}
if err := ctx . writeString ( errMsg ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot send error message %q to client: %w" , errMsg , err )
2020-02-13 15:32:54 +00:00
}
return nil
}
2019-05-22 21:23:23 +00:00
func ( ctx * vmselectRequestCtx ) writeString ( s string ) error {
ctx . dataBuf = append ( ctx . dataBuf [ : 0 ] , s ... )
return ctx . writeDataBufBytes ( )
}
func ( ctx * vmselectRequestCtx ) writeUint64 ( n uint64 ) error {
ctx . sizeBuf = encoding . MarshalUint64 ( ctx . sizeBuf [ : 0 ] , n )
if _ , err := ctx . bc . Write ( ctx . sizeBuf ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot write uint64 %d: %w" , n , err )
2019-05-22 21:23:23 +00:00
}
return nil
}
const maxRPCNameSize = 128
func ( s * Server ) processVMSelectRequest ( ctx * vmselectRequestCtx ) error {
// Read rpcName
// Do not set deadline on reading rpcName, since it may take a
// lot of time for idle connection.
if err := ctx . readDataBufBytes ( maxRPCNameSize ) ; err != nil {
if err == io . EOF {
// Remote client gracefully closed the connection.
return err
}
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot read rpcName: %w" , err )
2019-05-22 21:23:23 +00:00
}
2020-07-23 17:42:57 +00:00
rpcName := string ( ctx . dataBuf )
2019-05-22 21:23:23 +00:00
2022-05-31 23:31:40 +00:00
// Initialize query tracing.
traceEnabled , err := ctx . readBool ( )
if err != nil {
return fmt . Errorf ( "cannot read traceEnabled: %w" , err )
}
2022-06-08 18:05:17 +00:00
ctx . qt = querytracer . New ( traceEnabled , "%s() at vmstorage" , rpcName )
2022-05-31 23:31:40 +00:00
2019-05-22 21:23:23 +00:00
// Limit the time required for reading request args.
if err := ctx . bc . SetReadDeadline ( time . Now ( ) . Add ( 5 * time . Second ) ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot set read deadline for reading request args: %w" , err )
2019-05-22 21:23:23 +00:00
}
defer func ( ) {
2022-02-07 12:36:41 +00:00
_ = ctx . bc . SetReadDeadline ( time . Time { } )
2019-05-22 21:23:23 +00:00
} ( )
2020-07-23 17:42:57 +00:00
// Read the timeout for request execution.
timeout , err := ctx . readUint32 ( )
if err != nil {
return fmt . Errorf ( "cannot read timeout for the request %q: %w" , rpcName , err )
}
2020-08-10 10:17:12 +00:00
ctx . timeout = uint64 ( timeout )
2020-07-23 17:42:57 +00:00
ctx . deadline = fasttime . UnixTimestamp ( ) + uint64 ( timeout )
2022-05-31 23:31:40 +00:00
// Process the rpcName call.
if err := s . processVMSelectRPC ( ctx , rpcName ) ; err != nil {
2022-06-12 01:32:13 +00:00
return fmt . Errorf ( "cannot execute %q: %s" , rpcName , err )
2022-05-31 23:31:40 +00:00
}
// Finish query trace.
2022-06-08 18:05:17 +00:00
ctx . qt . Done ( )
2022-05-31 23:31:40 +00:00
traceJSON := ctx . qt . ToJSON ( )
if err := ctx . writeString ( traceJSON ) ; err != nil {
return fmt . Errorf ( "cannot send trace with length %d bytes to vmselect: %w" , len ( traceJSON ) , err )
}
return nil
}
func ( s * Server ) processVMSelectRPC ( ctx * vmselectRequestCtx , rpcName string ) error {
2020-07-23 17:42:57 +00:00
switch rpcName {
2022-05-31 23:31:40 +00:00
case "search_v6" :
2020-11-16 08:55:55 +00:00
return s . processVMSelectSearch ( ctx )
2022-05-31 23:31:40 +00:00
case "searchMetricNames_v3" :
2020-11-16 08:55:55 +00:00
return s . processVMSelectSearchMetricNames ( ctx )
2022-06-12 01:32:13 +00:00
case "labelValues_v5" :
2019-05-22 21:23:23 +00:00
return s . processVMSelectLabelValues ( ctx )
2022-05-31 23:31:40 +00:00
case "tagValueSuffixes_v3" :
2020-09-10 21:29:26 +00:00
return s . processVMSelectTagValueSuffixes ( ctx )
2022-06-12 01:32:13 +00:00
case "labelNames_v5" :
return s . processVMSelectLabelNames ( ctx )
2022-05-31 23:31:40 +00:00
case "seriesCount_v4" :
2019-05-22 21:23:23 +00:00
return s . processVMSelectSeriesCount ( ctx )
2022-06-14 14:46:16 +00:00
case "tsdbStatus_v5" :
2020-04-22 16:57:36 +00:00
return s . processVMSelectTSDBStatus ( ctx )
2022-05-31 23:31:40 +00:00
case "deleteMetrics_v5" :
2019-05-22 21:23:23 +00:00
return s . processVMSelectDeleteMetrics ( ctx )
2022-05-31 23:31:40 +00:00
case "registerMetricNames_v3" :
2020-11-23 10:33:17 +00:00
return s . processVMSelectRegisterMetricNames ( ctx )
2019-05-22 21:23:23 +00:00
default :
2022-06-12 01:32:13 +00:00
return fmt . Errorf ( "unsupported rpcName: %q" , rpcName )
2019-05-22 21:23:23 +00:00
}
}
2020-11-23 10:33:17 +00:00
const maxMetricNameRawSize = 1024 * 1024
const maxMetricNamesPerRequest = 1024 * 1024
func ( s * Server ) processVMSelectRegisterMetricNames ( ctx * vmselectRequestCtx ) error {
vmselectRegisterMetricNamesRequests . Inc ( )
// Read request
metricsCount , err := ctx . readUint64 ( )
if err != nil {
return fmt . Errorf ( "cannot read metricsCount: %w" , err )
}
if metricsCount > maxMetricNamesPerRequest {
return fmt . Errorf ( "too many metric names in a single request; got %d; mustn't exceed %d" , metricsCount , maxMetricNamesPerRequest )
}
mrs := make ( [ ] storage . MetricRow , metricsCount )
for i := 0 ; i < int ( metricsCount ) ; i ++ {
if err := ctx . readDataBufBytes ( maxMetricNameRawSize ) ; err != nil {
return fmt . Errorf ( "cannot read metricNameRaw: %w" , err )
}
mr := & mrs [ i ]
mr . MetricNameRaw = append ( mr . MetricNameRaw [ : 0 ] , ctx . dataBuf ... )
n , err := ctx . readUint64 ( )
if err != nil {
return fmt . Errorf ( "cannot read timestamp: %w" , err )
}
mr . Timestamp = int64 ( n )
}
// Register metric names from mrs.
if err := s . storage . RegisterMetricNames ( mrs ) ; err != nil {
return ctx . writeErrorMessage ( err )
}
// Send an empty error message to vmselect.
if err := ctx . writeString ( "" ) ; err != nil {
return fmt . Errorf ( "cannot send empty error message: %w" , err )
}
return nil
}
2019-05-22 21:23:23 +00:00
const maxTagFiltersSize = 64 * 1024
func ( s * Server ) processVMSelectDeleteMetrics ( ctx * vmselectRequestCtx ) error {
vmselectDeleteMetricsRequests . Inc ( )
// Read request
if err := ctx . readDataBufBytes ( maxTagFiltersSize ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot read labelName: %w" , err )
2019-05-22 21:23:23 +00:00
}
tail , err := ctx . sq . Unmarshal ( ctx . dataBuf )
if err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot unmarshal SearchQuery: %w" , err )
2019-05-22 21:23:23 +00:00
}
if len ( tail ) > 0 {
return fmt . Errorf ( "unexpected non-zero tail left after unmarshaling SearchQuery: (len=%d) %q" , len ( tail ) , tail )
}
// Setup ctx.tfss
2021-02-02 22:24:05 +00:00
tr := storage . TimeRange {
MinTimestamp : 0 ,
MaxTimestamp : time . Now ( ) . UnixNano ( ) / 1e6 ,
}
if err := ctx . setupTfss ( s . storage , tr ) ; err != nil {
2020-02-13 15:32:54 +00:00
return ctx . writeErrorMessage ( err )
2019-05-22 21:23:23 +00:00
}
// Delete the given metrics.
deletedCount , err := s . storage . DeleteMetrics ( ctx . tfss )
if err != nil {
2020-02-13 15:32:54 +00:00
return ctx . writeErrorMessage ( err )
2019-05-22 21:23:23 +00:00
}
// Send an empty error message to vmselect.
if err := ctx . writeString ( "" ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot send empty error message: %w" , err )
2019-05-22 21:23:23 +00:00
}
// Send deletedCount to vmselect.
if err := ctx . writeUint64 ( uint64 ( deletedCount ) ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot send deletedCount=%d: %w" , deletedCount , err )
2019-05-22 21:23:23 +00:00
}
return nil
}
2022-06-12 01:32:13 +00:00
func ( s * Server ) processVMSelectLabelNames ( ctx * vmselectRequestCtx ) error {
vmselectLabelNamesRequests . Inc ( )
2020-11-04 22:15:43 +00:00
// Read request
2022-06-12 01:32:13 +00:00
if err := ctx . readSearchQuery ( ) ; err != nil {
2022-06-10 06:50:30 +00:00
return err
}
2022-06-12 01:32:13 +00:00
maxLabelNames , err := ctx . readLimit ( )
2020-11-04 22:15:43 +00:00
if err != nil {
2022-06-12 01:32:13 +00:00
return fmt . Errorf ( "cannot read maxLabelNames: %w" , err )
2020-11-04 22:15:43 +00:00
}
2022-06-12 01:32:13 +00:00
if maxLabelNames <= 0 || maxLabelNames > * maxTagKeysPerSearch {
maxLabelNames = * maxTagKeysPerSearch
2020-11-04 22:15:43 +00:00
}
2022-06-12 01:32:13 +00:00
// Execute the request
tr := storage . TimeRange {
MinTimestamp : ctx . sq . MinTimestamp ,
MaxTimestamp : ctx . sq . MaxTimestamp ,
2022-06-10 06:50:30 +00:00
}
2022-06-12 01:32:13 +00:00
if err := ctx . setupTfss ( s . storage , tr ) ; err != nil {
return ctx . writeErrorMessage ( err )
2022-06-10 06:50:30 +00:00
}
2022-06-12 01:32:13 +00:00
maxMetrics := ctx . getMaxMetrics ( )
labelNames , err := s . storage . SearchLabelNamesWithFiltersOnTimeRange ( ctx . qt , ctx . sq . AccountID , ctx . sq . ProjectID , ctx . tfss , tr , maxLabelNames , maxMetrics , ctx . deadline )
2019-05-22 21:23:23 +00:00
if err != nil {
2020-02-13 15:32:54 +00:00
return ctx . writeErrorMessage ( err )
2019-05-22 21:23:23 +00:00
}
// Send an empty error message to vmselect.
if err := ctx . writeString ( "" ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot send empty error message: %w" , err )
2019-05-22 21:23:23 +00:00
}
2022-06-12 01:32:13 +00:00
// Send labelNames to vmselect
for _ , labelName := range labelNames {
if err := ctx . writeString ( labelName ) ; err != nil {
return fmt . Errorf ( "cannot write label name %q: %w" , labelName , err )
2019-05-22 21:23:23 +00:00
}
}
// Send 'end of response' marker
if err := ctx . writeString ( "" ) ; err != nil {
return fmt . Errorf ( "cannot send 'end of response' marker" )
}
return nil
}
const maxLabelValueSize = 16 * 1024
2022-06-12 01:32:13 +00:00
func ( s * Server ) processVMSelectLabelValues ( ctx * vmselectRequestCtx ) error {
vmselectLabelValuesRequests . Inc ( )
2020-11-04 22:15:43 +00:00
// Read request
2020-11-05 00:07:59 +00:00
if err := ctx . readDataBufBytes ( maxLabelValueSize ) ; err != nil {
return fmt . Errorf ( "cannot read labelName: %w" , err )
}
labelName := string ( ctx . dataBuf )
2022-06-12 01:32:13 +00:00
if err := ctx . readSearchQuery ( ) ; err != nil {
2020-11-04 22:15:43 +00:00
return err
}
2022-06-12 01:32:13 +00:00
maxLabelValues , err := ctx . readLimit ( )
2022-06-10 06:50:30 +00:00
if err != nil {
2022-06-12 01:32:13 +00:00
return fmt . Errorf ( "cannot read maxLabelValues: %w" , err )
2022-06-10 06:50:30 +00:00
}
2022-06-12 01:32:13 +00:00
if maxLabelValues <= 0 || maxLabelValues > * maxTagValuesPerSearch {
maxLabelValues = * maxTagValuesPerSearch
2022-06-10 06:50:30 +00:00
}
2020-11-04 22:15:43 +00:00
2022-06-12 01:32:13 +00:00
// Execute the request
tr := storage . TimeRange {
MinTimestamp : ctx . sq . MinTimestamp ,
MaxTimestamp : ctx . sq . MaxTimestamp ,
}
if err := ctx . setupTfss ( s . storage , tr ) ; err != nil {
return ctx . writeErrorMessage ( err )
}
maxMetrics := ctx . getMaxMetrics ( )
labelValues , err := s . storage . SearchLabelValuesWithFiltersOnTimeRange ( ctx . qt , ctx . sq . AccountID , ctx . sq . ProjectID , labelName , ctx . tfss , tr ,
maxLabelValues , maxMetrics , ctx . deadline )
2020-11-04 22:15:43 +00:00
if err != nil {
return ctx . writeErrorMessage ( err )
}
// Send an empty error message to vmselect.
if err := ctx . writeString ( "" ) ; err != nil {
return fmt . Errorf ( "cannot send empty error message: %w" , err )
}
2022-06-12 01:32:13 +00:00
// Send labelValues to vmselect
for _ , labelValue := range labelValues {
if len ( labelValue ) == 0 {
// Skip empty label values, since they have no sense for prometheus.
continue
}
if err := ctx . writeString ( labelValue ) ; err != nil {
return fmt . Errorf ( "cannot write labelValue %q: %w" , labelValue , err )
}
2019-05-22 21:23:23 +00:00
}
2022-06-12 01:32:13 +00:00
// Send 'end of label values' marker
2019-05-22 21:23:23 +00:00
if err := ctx . writeString ( "" ) ; err != nil {
2022-06-12 01:32:13 +00:00
return fmt . Errorf ( "cannot send 'end of response' marker" )
2019-05-22 21:23:23 +00:00
}
2022-06-12 01:32:13 +00:00
return nil
2019-06-10 15:55:20 +00:00
}
2020-09-10 21:29:26 +00:00
func ( s * Server ) processVMSelectTagValueSuffixes ( ctx * vmselectRequestCtx ) error {
vmselectTagValueSuffixesRequests . Inc ( )
// read request
accountID , projectID , err := ctx . readAccountIDProjectID ( )
if err != nil {
return err
}
2020-11-04 22:15:43 +00:00
tr , err := ctx . readTimeRange ( )
2020-09-10 21:29:26 +00:00
if err != nil {
2020-11-04 22:15:43 +00:00
return err
2020-09-10 21:29:26 +00:00
}
if err := ctx . readDataBufBytes ( maxLabelValueSize ) ; err != nil {
return fmt . Errorf ( "cannot read tagKey: %w" , err )
}
tagKey := append ( [ ] byte { } , ctx . dataBuf ... )
if err := ctx . readDataBufBytes ( maxLabelValueSize ) ; err != nil {
return fmt . Errorf ( "cannot read tagValuePrefix: %w" , err )
}
tagValuePrefix := append ( [ ] byte { } , ctx . dataBuf ... )
delimiter , err := ctx . readByte ( )
if err != nil {
2020-09-23 19:46:24 +00:00
return fmt . Errorf ( "cannot read delimiter: %w" , err )
2020-09-10 21:29:26 +00:00
}
// Search for tag value suffixes
suffixes , err := s . storage . SearchTagValueSuffixes ( accountID , projectID , tr , tagKey , tagValuePrefix , delimiter , * maxTagValueSuffixesPerSearch , ctx . deadline )
if err != nil {
return ctx . writeErrorMessage ( err )
}
2021-02-02 22:24:05 +00:00
if len ( suffixes ) >= * maxTagValueSuffixesPerSearch {
err := fmt . Errorf ( "more than -search.maxTagValueSuffixesPerSearch=%d tag value suffixes found " +
"for tagKey=%q, tagValuePrefix=%q, delimiter=%c on time range %s; " +
"either narrow down the query or increase -search.maxTagValueSuffixesPerSearch command-line flag value" ,
* maxTagValueSuffixesPerSearch , tagKey , tagValuePrefix , delimiter , tr . String ( ) )
return ctx . writeErrorMessage ( err )
}
2020-09-10 21:29:26 +00:00
// Send an empty error message to vmselect.
if err := ctx . writeString ( "" ) ; err != nil {
return fmt . Errorf ( "cannot send empty error message: %w" , err )
}
// Send suffixes to vmselect.
// Suffixes may contain empty string, so prepend suffixes with suffixCount.
if err := ctx . writeUint64 ( uint64 ( len ( suffixes ) ) ) ; err != nil {
return fmt . Errorf ( "cannot write suffixesCount: %w" , err )
}
for i , suffix := range suffixes {
if err := ctx . writeString ( suffix ) ; err != nil {
return fmt . Errorf ( "cannot write suffix #%d: %w" , i + 1 , err )
}
}
return nil
}
2019-05-22 21:23:23 +00:00
func ( s * Server ) processVMSelectSeriesCount ( ctx * vmselectRequestCtx ) error {
vmselectSeriesCountRequests . Inc ( )
// Read request
2020-09-10 21:29:26 +00:00
accountID , projectID , err := ctx . readAccountIDProjectID ( )
2019-05-22 21:23:23 +00:00
if err != nil {
2020-09-10 21:29:26 +00:00
return err
2019-05-22 21:23:23 +00:00
}
// Execute the request
2020-07-23 17:42:57 +00:00
n , err := s . storage . GetSeriesCount ( accountID , projectID , ctx . deadline )
2019-05-22 21:23:23 +00:00
if err != nil {
2020-02-13 15:32:54 +00:00
return ctx . writeErrorMessage ( err )
2019-05-22 21:23:23 +00:00
}
// Send an empty error message to vmselect.
if err := ctx . writeString ( "" ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot send empty error message: %w" , err )
2019-05-22 21:23:23 +00:00
}
// Send series count to vmselect.
if err := ctx . writeUint64 ( n ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot write series count to vmselect: %w" , err )
2019-05-22 21:23:23 +00:00
}
return nil
}
2020-04-22 16:57:36 +00:00
func ( s * Server ) processVMSelectTSDBStatus ( ctx * vmselectRequestCtx ) error {
vmselectTSDBStatusRequests . Inc ( )
// Read request
2022-06-14 14:46:16 +00:00
if err := ctx . readSearchQuery ( ) ; err != nil {
2020-09-10 21:29:26 +00:00
return err
2020-04-22 16:57:36 +00:00
}
2022-06-14 14:46:16 +00:00
if err := ctx . readDataBufBytes ( maxLabelValueSize ) ; err != nil {
return fmt . Errorf ( "cannot read focusLabel: %w" , err )
2020-04-22 16:57:36 +00:00
}
2022-06-14 14:46:16 +00:00
focusLabel := string ( ctx . dataBuf )
2020-04-22 16:57:36 +00:00
topN , err := ctx . readUint32 ( )
if err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot read topN: %w" , err )
2020-04-22 16:57:36 +00:00
}
// Execute the request
2022-06-14 14:46:16 +00:00
tr := storage . TimeRange {
MinTimestamp : ctx . sq . MinTimestamp ,
MaxTimestamp : ctx . sq . MaxTimestamp ,
}
if err := ctx . setupTfss ( s . storage , tr ) ; err != nil {
return ctx . writeErrorMessage ( err )
}
maxMetrics := ctx . getMaxMetrics ( )
date := uint64 ( ctx . sq . MinTimestamp ) / ( 24 * 3600 * 1000 )
status , err := s . storage . GetTSDBStatus ( ctx . qt , ctx . sq . AccountID , ctx . sq . ProjectID , ctx . tfss , date , focusLabel , int ( topN ) , maxMetrics , ctx . deadline )
2020-04-22 16:57:36 +00:00
if err != nil {
return ctx . writeErrorMessage ( err )
}
// Send an empty error message to vmselect.
if err := ctx . writeString ( "" ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot send empty error message: %w" , err )
2020-04-22 16:57:36 +00:00
}
// Send status to vmselect.
2022-06-08 16:25:59 +00:00
return writeTSDBStatus ( ctx , status )
}
func writeTSDBStatus ( ctx * vmselectRequestCtx , status * storage . TSDBStatus ) error {
2022-06-16 07:44:29 +00:00
if err := ctx . writeUint64 ( status . TotalSeries ) ; err != nil {
return fmt . Errorf ( "cannot write totalSeries to vmselect: %w" , err )
}
if err := ctx . writeUint64 ( status . TotalLabelValuePairs ) ; err != nil {
return fmt . Errorf ( "cannot write totalLabelValuePairs to vmselect: %w" , err )
}
2020-04-22 16:57:36 +00:00
if err := writeTopHeapEntries ( ctx , status . SeriesCountByMetricName ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot write seriesCountByMetricName to vmselect: %w" , err )
2020-04-22 16:57:36 +00:00
}
2022-06-16 07:44:29 +00:00
if err := writeTopHeapEntries ( ctx , status . SeriesCountByLabelName ) ; err != nil {
return fmt . Errorf ( "cannot write seriesCountByLabelName to vmselect: %w" , err )
}
if err := writeTopHeapEntries ( ctx , status . SeriesCountByFocusLabelValue ) ; err != nil {
return fmt . Errorf ( "cannot write seriesCountByFocusLabelValue to vmselect: %w" , err )
2020-04-22 16:57:36 +00:00
}
if err := writeTopHeapEntries ( ctx , status . SeriesCountByLabelValuePair ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot write seriesCountByLabelValuePair to vmselect: %w" , err )
2020-04-22 16:57:36 +00:00
}
2022-06-16 07:44:29 +00:00
if err := writeTopHeapEntries ( ctx , status . LabelValueCountByLabelName ) ; err != nil {
return fmt . Errorf ( "cannot write labelValueCountByLabelName to vmselect: %w" , err )
2022-06-08 15:43:05 +00:00
}
2020-04-22 16:57:36 +00:00
return nil
}
func writeTopHeapEntries ( ctx * vmselectRequestCtx , a [ ] storage . TopHeapEntry ) error {
if err := ctx . writeUint64 ( uint64 ( len ( a ) ) ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot write topHeapEntries size: %w" , err )
2020-04-22 16:57:36 +00:00
}
for _ , e := range a {
if err := ctx . writeString ( e . Name ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot write topHeapEntry name: %w" , err )
2020-04-22 16:57:36 +00:00
}
if err := ctx . writeUint64 ( e . Count ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot write topHeapEntry count: %w" , err )
2020-04-22 16:57:36 +00:00
}
}
return nil
}
2019-05-22 21:23:23 +00:00
// maxSearchQuerySize is the maximum size of SearchQuery packet in bytes.
const maxSearchQuerySize = 1024 * 1024
2020-11-16 08:55:55 +00:00
func ( s * Server ) processVMSelectSearchMetricNames ( ctx * vmselectRequestCtx ) error {
vmselectSearchMetricNamesRequests . Inc ( )
2019-05-22 21:23:23 +00:00
2020-11-16 08:55:55 +00:00
// Read request.
if err := ctx . readSearchQuery ( ) ; err != nil {
return err
2019-05-22 21:23:23 +00:00
}
2020-11-16 08:55:55 +00:00
// Search metric names.
tr := storage . TimeRange {
MinTimestamp : ctx . sq . MinTimestamp ,
MaxTimestamp : ctx . sq . MaxTimestamp ,
}
2021-02-02 22:24:05 +00:00
if err := ctx . setupTfss ( s . storage , tr ) ; err != nil {
return ctx . writeErrorMessage ( err )
}
2022-03-26 08:17:37 +00:00
maxMetrics := ctx . getMaxMetrics ( )
2022-05-31 23:31:40 +00:00
mns , err := s . storage . SearchMetricNames ( ctx . qt , ctx . tfss , tr , maxMetrics , ctx . deadline )
2019-05-22 21:23:23 +00:00
if err != nil {
2020-11-16 08:55:55 +00:00
return ctx . writeErrorMessage ( err )
2019-05-22 21:23:23 +00:00
}
2020-11-16 08:55:55 +00:00
// Send empty error message to vmselect.
if err := ctx . writeString ( "" ) ; err != nil {
return fmt . Errorf ( "cannot send empty error message: %w" , err )
}
// Send response.
metricNamesCount := len ( mns )
if err := ctx . writeUint64 ( uint64 ( metricNamesCount ) ) ; err != nil {
return fmt . Errorf ( "cannot send metricNamesCount: %w" , err )
}
for i , mn := range mns {
ctx . dataBuf = mn . Marshal ( ctx . dataBuf [ : 0 ] )
if err := ctx . writeDataBufBytes ( ) ; err != nil {
return fmt . Errorf ( "cannot send metricName #%d: %w" , i + 1 , err )
}
}
2022-05-31 23:31:40 +00:00
ctx . qt . Printf ( "sent %d series to vmselect" , len ( mns ) )
2020-11-16 08:55:55 +00:00
return nil
}
func ( s * Server ) processVMSelectSearch ( ctx * vmselectRequestCtx ) error {
vmselectSearchRequests . Inc ( )
// Read request.
if err := ctx . readSearchQuery ( ) ; err != nil {
return err
2019-05-22 21:23:23 +00:00
}
2019-08-04 19:15:33 +00:00
fetchData , err := ctx . readBool ( )
if err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot read `fetchData` bool: %w" , err )
2019-08-04 19:15:33 +00:00
}
2019-05-22 21:23:23 +00:00
// Setup search.
tr := storage . TimeRange {
MinTimestamp : ctx . sq . MinTimestamp ,
MaxTimestamp : ctx . sq . MaxTimestamp ,
}
2021-02-02 22:24:05 +00:00
if err := ctx . setupTfss ( s . storage , tr ) ; err != nil {
return ctx . writeErrorMessage ( err )
}
2020-06-30 21:58:26 +00:00
if err := checkTimeRange ( s . storage , tr ) ; err != nil {
return ctx . writeErrorMessage ( err )
}
2021-03-16 23:12:28 +00:00
startTime := time . Now ( )
2022-03-26 08:17:37 +00:00
maxMetrics := ctx . getMaxMetrics ( )
2022-05-31 23:31:40 +00:00
ctx . sr . Init ( ctx . qt , s . storage , ctx . tfss , tr , maxMetrics , ctx . deadline )
2021-03-16 23:12:28 +00:00
indexSearchDuration . UpdateDuration ( startTime )
2019-05-22 21:23:23 +00:00
defer ctx . sr . MustClose ( )
if err := ctx . sr . Error ( ) ; err != nil {
2020-02-13 15:32:54 +00:00
return ctx . writeErrorMessage ( err )
2019-05-22 21:23:23 +00:00
}
// Send empty error message to vmselect.
if err := ctx . writeString ( "" ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot send empty error message: %w" , err )
2019-05-22 21:23:23 +00:00
}
// Send found blocks to vmselect.
2022-05-31 23:31:40 +00:00
blocksRead := 0
2019-05-22 21:23:23 +00:00
for ctx . sr . NextMetricBlock ( ) {
2022-05-31 23:31:40 +00:00
blocksRead ++
2020-04-27 05:13:41 +00:00
ctx . mb . MetricName = ctx . sr . MetricBlockRef . MetricName
ctx . sr . MetricBlockRef . BlockRef . MustReadBlock ( & ctx . mb . Block , fetchData )
2019-05-22 21:23:23 +00:00
vmselectMetricBlocksRead . Inc ( )
2021-07-28 14:40:09 +00:00
vmselectMetricRowsRead . Add ( ctx . mb . Block . RowsCount ( ) )
2019-05-22 21:23:23 +00:00
2020-04-27 05:13:41 +00:00
ctx . dataBuf = ctx . mb . Marshal ( ctx . dataBuf [ : 0 ] )
2019-05-22 21:23:23 +00:00
if err := ctx . writeDataBufBytes ( ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot send MetricBlock: %w" , err )
2019-05-22 21:23:23 +00:00
}
}
if err := ctx . sr . Error ( ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "search error: %w" , err )
2019-05-22 21:23:23 +00:00
}
2022-05-31 23:31:40 +00:00
ctx . qt . Printf ( "sent %d blocks to vmselect" , blocksRead )
2019-05-22 21:23:23 +00:00
// Send 'end of response' marker
if err := ctx . writeString ( "" ) ; err != nil {
return fmt . Errorf ( "cannot send 'end of response' marker" )
}
return nil
}
2021-03-16 23:12:28 +00:00
var indexSearchDuration = metrics . NewHistogram ( ` vm_index_search_duration_seconds ` )
2020-06-30 21:58:26 +00:00
// checkTimeRange returns true if the given tr is denied for querying.
func checkTimeRange ( s * storage . Storage , tr storage . TimeRange ) error {
if ! * denyQueriesOutsideRetention {
return nil
}
2020-10-20 13:10:46 +00:00
retentionMsecs := s . RetentionMsecs ( )
minAllowedTimestamp := int64 ( fasttime . UnixTimestamp ( ) * 1000 ) - retentionMsecs
2020-06-30 21:58:26 +00:00
if tr . MinTimestamp > minAllowedTimestamp {
return nil
}
return & httpserver . ErrorWithStatusCode {
2020-10-20 13:10:46 +00:00
Err : fmt . Errorf ( "the given time range %s is outside the allowed retention %.3f days according to -denyQueriesOutsideRetention" ,
& tr , float64 ( retentionMsecs ) / ( 24 * 3600 * 1000 ) ) ,
2020-06-30 21:58:26 +00:00
StatusCode : http . StatusServiceUnavailable ,
}
}
2019-05-22 21:23:23 +00:00
var (
2022-06-14 14:46:16 +00:00
vmselectRegisterMetricNamesRequests = metrics . NewCounter ( ` vm_vmselect_rpc_requests_total { name="register_metric_names"} ` )
vmselectDeleteMetricsRequests = metrics . NewCounter ( ` vm_vmselect_rpc_requests_total { name="delete_metrics"} ` )
vmselectLabelNamesRequests = metrics . NewCounter ( ` vm_vmselect_rpc_requests_total { name="label_names"} ` )
vmselectLabelValuesRequests = metrics . NewCounter ( ` vm_vmselect_rpc_requests_total { name="label_values"} ` )
vmselectTagValueSuffixesRequests = metrics . NewCounter ( ` vm_vmselect_rpc_requests_total { name="tag_value_suffixes"} ` )
vmselectSeriesCountRequests = metrics . NewCounter ( ` vm_vmselect_rpc_requests_total { name="series_count"} ` )
vmselectTSDBStatusRequests = metrics . NewCounter ( ` vm_vmselect_rpc_requests_total { name="tsdb_status"} ` )
vmselectSearchMetricNamesRequests = metrics . NewCounter ( ` vm_vmselect_rpc_requests_total { name="search_metric_names"} ` )
vmselectSearchRequests = metrics . NewCounter ( ` vm_vmselect_rpc_requests_total { name="search"} ` )
2020-11-23 10:33:17 +00:00
vmselectMetricBlocksRead = metrics . NewCounter ( ` vm_vmselect_metric_blocks_read_total ` )
vmselectMetricRowsRead = metrics . NewCounter ( ` vm_vmselect_metric_rows_read_total ` )
2019-05-22 21:23:23 +00:00
)
2022-03-26 08:17:37 +00:00
func ( ctx * vmselectRequestCtx ) getMaxMetrics ( ) int {
maxMetrics := ctx . sq . MaxMetrics
2022-04-12 08:19:04 +00:00
maxMetricsLimit := * maxMetricsPerSearch
if maxMetricsLimit <= 0 {
maxMetricsLimit = 2e9
2022-03-26 08:17:37 +00:00
}
2022-04-12 08:19:04 +00:00
if maxMetrics <= 0 || maxMetrics > maxMetricsLimit {
maxMetrics = maxMetricsLimit
2022-03-26 08:17:37 +00:00
}
return maxMetrics
}
2021-02-02 22:24:05 +00:00
func ( ctx * vmselectRequestCtx ) setupTfss ( s * storage . Storage , tr storage . TimeRange ) error {
2019-05-22 21:23:23 +00:00
tfss := ctx . tfss [ : 0 ]
2021-02-02 22:24:05 +00:00
accountID := ctx . sq . AccountID
projectID := ctx . sq . ProjectID
2019-05-22 21:23:23 +00:00
for _ , tagFilters := range ctx . sq . TagFilterss {
2021-02-02 22:24:05 +00:00
tfs := storage . NewTagFilters ( accountID , projectID )
2019-05-22 21:23:23 +00:00
for i := range tagFilters {
tf := & tagFilters [ i ]
2021-02-02 22:24:05 +00:00
if string ( tf . Key ) == "__graphite__" {
query := tf . Value
2022-03-26 08:17:37 +00:00
maxMetrics := ctx . getMaxMetrics ( )
paths , err := s . SearchGraphitePaths ( accountID , projectID , tr , query , maxMetrics , ctx . deadline )
2021-02-02 22:24:05 +00:00
if err != nil {
return fmt . Errorf ( "error when searching for Graphite paths for query %q: %w" , query , err )
}
2022-03-26 08:17:37 +00:00
if len ( paths ) >= maxMetrics {
return fmt . Errorf ( "more than %d time series match Graphite query %q; " +
"either narrow down the query or increase the corresponding -search.max* command-line flag value at vmselect nodes" , maxMetrics , query )
2021-02-02 22:24:05 +00:00
}
tfs . AddGraphiteQuery ( query , paths , tf . IsNegative )
continue
}
2019-05-22 21:23:23 +00:00
if err := tfs . Add ( tf . Key , tf . Value , tf . IsNegative , tf . IsRegexp ) ; err != nil {
2020-06-30 19:58:18 +00:00
return fmt . Errorf ( "cannot parse tag filter %s: %w" , tf , err )
2019-05-22 21:23:23 +00:00
}
}
2020-06-05 10:17:23 +00:00
tfss = append ( tfss , tfs )
2019-05-22 21:23:23 +00:00
}
ctx . tfss = tfss
return nil
}